1 /*******************************************************************************
2  * Copyright (c) 2011 LWJGL Project and others
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html, and under the terms of the
7  * BSD license, see http://lwjgl.org/license.php for details.
8  *
9  * Contributors:
10  *    Jens von Pilgrim - initial implementation
11  ******************************************************************************/
12 package org.lwjgl.ant;
13 
14 import java.io.File;
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.util.Date;
18 import java.util.HashSet;
19 import java.util.Iterator;
20 import java.util.Set;
21 import java.util.StringTokenizer;
22 import java.util.TreeMap;
23 import java.util.Vector;
24 
25 import org.apache.tools.ant.BuildException;
26 import org.apache.tools.ant.taskdefs.Expand;
27 import org.apache.tools.ant.types.PatternSet;
28 import org.apache.tools.ant.types.selectors.SelectorUtils;
29 import org.apache.tools.ant.util.FileNameMapper;
30 import org.apache.tools.ant.util.FileUtils;
31 
32 /**
33  * Ant task extracting package names (or generally directory names) into given
34  * property.
35  *
36  * Parameters:
37  * - just like unzip, except dest can be null and is ignored otherwise
38  * - property - name of property storing the resulting list
39  * - pathsep - path separator, default ","
40  * - dirsep - directory separator, default "."
41  * - includeemptydirs -- whether to include empty directories, default: false
42  *
43  * @author 	Jens von Pilgrim
44  * @since 	12.09.2007
45  */
46 public class PackageList extends Expand {
47 
48 	/**
49 	* The property to receive the conversion
50 	*/
51 	private String property = null;
52 
53 	/**
54 	 * User override on path sep char
55 	 */
56 	private String pathSep = ",";
57 
58 	/**
59 	 * User override on directory sep char
60 	 */
61 	private String dirSep = ".";
62 
63 
64 	private boolean includeemptydirs = false;
65 
66 	class IntegerContainer {
67 		int value;
68 
inc()69 		public void inc() {
70 			value++;
71 		}
72 	};
73 
74 	TreeMap<String, IntegerContainer> packagelist = new TreeMap<String, IntegerContainer>();
75 
76 	/**
77 	 * {@inheritDoc}
78 	 * @see org.apache.tools.ant.taskdefs.Expand#execute()
79 	 */
80 	@Override
execute()81 	public void execute() throws BuildException {
82 
83 		setDest(new File(" no file, files are only listed internaly"));
84 		super.execute();
85 
86 		StringBuffer strb = new StringBuffer();
87 		for (String name : packagelist.keySet()) {
88 
89 			// System.out.println("name: " + name + " (" +packagelist.get(name).value + ")" );
90 
91 			if (includeemptydirs || packagelist.get(name).value > 0) {
92 				if (strb.length() > 0) {
93 					strb.append(pathSep);
94 				}
95 				StringTokenizer stDirectory = new StringTokenizer(name, "/",
96 						true);
97 
98 				while (stDirectory.hasMoreTokens()) {
99 					String token = stDirectory.nextToken();
100 					strb.append("/".equals(token) ? dirSep : token);
101 				}
102 			}
103 		}
104 
105 		if (property != null) {
106 			String value = strb.toString();
107 			getProject().setNewProperty(property, value);
108 		}
109 
110 	}
111 
112 	private Vector<PatternSet> patternsets = new Vector<PatternSet>();
113 
114 	/**
115 	 * Add a patternset.
116 	 * @param set a pattern set
117 	 */
addPatternset(PatternSet set)118 	public void addPatternset(PatternSet set) {
119 		super.addPatternset(set);
120 		patternsets.addElement(set);
121 	}
122 
123 	/**
124 	 * {@inheritDoc}
125 	 * @see org.apache.tools.ant.taskdefs.Expand#extractFile(org.apache.tools.ant.util.FileUtils, java.io.File, java.io.File, java.io.InputStream, java.lang.String, java.util.Date, boolean, org.apache.tools.ant.util.FileNameMapper)
126 	 */
127 	@Override
extractFile(FileUtils i_fileUtils, File i_srcF, File i_dir, InputStream i_compressedInputStream, String i_entryName, Date i_entryDate, boolean i_isDirectory, FileNameMapper i_mapper)128 	protected void extractFile(FileUtils i_fileUtils, File i_srcF, File i_dir,
129 			InputStream i_compressedInputStream, String i_entryName,
130 			Date i_entryDate, boolean i_isDirectory, FileNameMapper i_mapper)
131 			throws IOException {
132 
133 		if (!matchPatterns(i_entryName)) {
134 			//Do not process this file
135 			return;
136 		}
137 
138 		String strDir = getDir(i_isDirectory, i_entryName);
139 		if (strDir != null && !"META-INF".equals(strDir)) {
140 			if (!packagelist.containsKey(strDir)) {
141 				packagelist.put(strDir, new IntegerContainer());
142 			}
143 			if (!i_isDirectory) {
144 				packagelist.get(strDir).inc();
145 			}
146 		}
147 
148 	}
149 
150 	/**
151 	 * @param i_entryName
152 	 */
matchPatterns(String i_entryName)153 	private boolean matchPatterns(String i_entryName) {
154 		if (patternsets != null && patternsets.size() > 0) {
155 			boolean included = false;
156 			String name = i_entryName.replace('/', File.separatorChar).replace(
157 					'\\', File.separatorChar);
158 
159 			Set<String> includePatterns = new HashSet<String>();
160 			Set<String> excludePatterns = new HashSet<String>();
161 			for (int v = 0, size = patternsets.size(); v < size; v++) {
162 				PatternSet p = (PatternSet) patternsets.elementAt(v);
163 				String[] incls = p.getIncludePatterns(getProject());
164 				if (incls == null || incls.length == 0) {
165 					// no include pattern implicitly means includes="**"
166 					incls = new String[] { "**" };
167 				}
168 
169 				for (int w = 0; w < incls.length; w++) {
170 					String pattern = incls[w].replace('/', File.separatorChar)
171 							.replace('\\', File.separatorChar);
172 					if (pattern.endsWith(File.separator)) {
173 						pattern += "**";
174 					}
175 					includePatterns.add(pattern);
176 				}
177 
178 				String[] excls = p.getExcludePatterns(getProject());
179 				if (excls != null) {
180 					for (int w = 0; w < excls.length; w++) {
181 						String pattern = excls[w].replace('/',
182 								File.separatorChar).replace('\\',
183 								File.separatorChar);
184 						if (pattern.endsWith(File.separator)) {
185 							pattern += "**";
186 						}
187 						excludePatterns.add(pattern);
188 					}
189 				}
190 			}
191 
192 			for (Iterator<String> iter = includePatterns.iterator(); !included
193 					&& iter.hasNext();) {
194 				String pattern = iter.next();
195 				included = SelectorUtils.matchPath(pattern, name);
196 			}
197 
198 			for (Iterator<String> iter = excludePatterns.iterator(); included
199 					&& iter.hasNext();) {
200 				String pattern =  iter.next();
201 				included = !SelectorUtils.matchPath(pattern, name);
202 			}
203 
204 			return included;
205 		}
206 		return true;
207 	}
208 
209 	/**
210 	 * @param i_isDirectory
211 	 * @param i_entryName
212 	 * @return
213 	 */
getDir(boolean i_isDirectory, String i_entryName)214 	private String getDir(boolean i_isDirectory, String i_entryName) {
215 
216 		if (i_entryName == null)
217 			return null;
218 		int iIndex = i_entryName.lastIndexOf('/');
219 		if (iIndex >= 0) {
220 			return i_entryName.substring(0, iIndex);
221 		}
222 		if (i_isDirectory) {
223 			return i_entryName;
224 		}
225 		return null;
226 	}
227 
228 	/**
229 	 * Set the name of the property into which the converted path will be placed.
230 	 * @param p the property name.
231 	 */
setProperty(String p)232 	public void setProperty(String p) {
233 		property = p;
234 	}
235 
236 	/**
237 	 * Set the default path separator string; defaults to current JVM
238 	 * {@link java.io.File#pathSeparator File.pathSeparator}.
239 	 * @param sep path separator string.
240 	 */
setPathSep(String sep)241 	public void setPathSep(String sep) {
242 		pathSep = sep;
243 	}
244 
245 	/**
246 	 * Set the default directory separator string;
247 	 * defaults to current JVM {@link java.io.File#separator File.separator}.
248 	 * @param sep directory separator string.
249 	 */
setDirSep(String sep)250 	public void setDirSep(String sep) {
251 		dirSep = sep;
252 	}
253 
254 	/**
255 	 * Simple getter for attribute includeemptydirs.
256 	 * @return the includeemptydirs
257 	 */
isIncludeemptydirs()258 	public boolean isIncludeemptydirs() {
259 		return includeemptydirs;
260 	}
261 
262 	/**
263 	 * Simple setter for attribute includeemptydirs.
264 	 * @param i_includeemptydirs the includeemptydirs to set
265 	 */
setIncludeemptydirs(boolean i_includeemptydirs)266 	public void setIncludeemptydirs(boolean i_includeemptydirs) {
267 		includeemptydirs = i_includeemptydirs;
268 	}
269 
270 }
271