View Javadoc

1    /*
2     * This is free software; you can redistribute it and/or modify it
3     * under the terms of the GNU Lesser General Public License as
4     * published by the Free Software Foundation; either version 2.1 of
5     * the License, or (at your option) any later version.
6     *
7     * This software is distributed in the hope that it will be useful,
8     * but WITHOUT ANY WARRANTY; without even the implied warranty of
9     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10    * Lesser General Public License for more details.
11    *
12    * You should have received a copy of the GNU Lesser General Public
13    * License along with this software; if not, write to the Free
14    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
15    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
16    */
17  
18  package installtoolkit.wix;
19  
20  import java.io.File;
21  import java.io.FileWriter;
22  import java.io.IOException;
23  import java.util.ArrayList;
24  import java.util.List;
25  import java.util.UUID;
26  
27  import org.apache.tools.ant.BuildException;
28  import org.apache.tools.ant.Task;
29  import org.apache.tools.ant.types.Path;
30  import org.dom4j.Document;
31  import org.dom4j.DocumentHelper;
32  import org.dom4j.Element;
33  import org.dom4j.io.OutputFormat;
34  import org.dom4j.io.XMLWriter;
35  
36  /**
37   * Task to generate a WiX fragment file containing a file hierachie
38   * build from a directory structure.
39   *  
40   * @author Christian Elberfeld <elberfeld@web.de>
41   */
42  public class FilesFragmentGeneratorTask extends Task {
43  	
44  	private boolean debug = false;
45  	private String fragmentid;
46  	private String directoryid;
47  	private String featureid;	
48  	private File destdir;
49  	private String filename = "FilesFragment.wxs";
50  	private String idprefix = "";
51  	private File srcdir;
52  	private String diskid = "1";
53  	private String startmenuefolder;
54  
55  	private Path configfiles;
56  	private List<Shortcut> desktopshortcuts = new ArrayList<Shortcut>();
57  	private List<Shortcut> startmenueshortcuts = new ArrayList<Shortcut>();
58  	
59  	private IdGenarator idgen;
60  	private FilenameGenarator namegen;
61  	private List<File> configs;
62  	private Document document;
63  	private Element fragment;
64  	private Element feature;
65  
66  	
67  	/**
68  	 * @see Task#execute()
69  	 */
70  	@Override
71  	public void execute() throws BuildException {
72  
73  		try {
74  			
75  			if (debug) handleOutput("starting execute()");
76  			
77  			if (this.fragmentid == null) throw new BuildException("Attribute \"fragmentid\" must be set");		
78  			if (this.directoryid == null) throw new BuildException("Attribute \"directoryid\" must be set");		
79  			if (this.featureid == null) throw new BuildException("Attribute \"featureid\" must be set");		
80  			if (this.destdir == null) throw new BuildException("Attribute \"destdir\" must be set");		
81  			if (this.srcdir == null) throw new BuildException("Attribute \"srcdir\" must be set");		
82  
83  			this.idgen = new IdGenarator(10,this.idprefix);
84  			this.namegen = new FilenameGenarator();
85  			
86  			this.configs = new ArrayList<File>();
87  			
88  			if (this.configfiles != null) {
89  			
90  				String[] configfiles_list = this.configfiles.list();
91  				if (debug) handleOutput("Number of Configfiles: "+configfiles_list.length);
92  				
93  				for (String name : configfiles_list) {
94  					
95  					File f = this.getProject().resolveFile(name);
96  					configs.add(f);
97  					if (debug) handleOutput("Config File: "+f.getAbsolutePath());
98  					
99  				} // for
100 
101 			} else {
102 				
103 				if (debug) handleOutput("No Config Files ... ");
104 			} // if else
105 			
106 			
107 			this.document = DocumentHelper.createDocument();
108 			Element wix = document.addElement( "Wix" , "http://schemas.microsoft.com/wix/2003/01/wi");
109 
110 			this.fragment = wix.addElement("Fragment");
111 			fragment.addAttribute("Id",this.fragmentid);
112 
113 			Element dir = fragment.addElement("DirectoryRef");
114 			dir.addAttribute("Id",this.directoryid);
115 
116 			Element desktop = dir.addElement("Directory");
117 			desktop.addAttribute("Id",this.idprefix + "DesktopFolder");
118 			desktop.addAttribute("Name","Desktop");
119 			
120 			Element startmenue = dir.addElement("Directory");
121 			startmenue.addAttribute("Id",this.idprefix + "ProgramMenuFolder");
122 			startmenue.addAttribute("Name","PMenu");
123 						
124 			if (startmenuefolder != null) {
125 				
126 				Element startmenue_dir = startmenue.addElement("Directory");
127 				startmenue_dir.addAttribute("Id",this.idprefix + "Start_Menue_Folder");				
128 				
129 				if (this.startmenuefolder.length() > 8) {
130 					
131 					startmenue_dir.addAttribute("LongName",this.startmenuefolder);
132 					startmenue_dir.addAttribute("Name",this.startmenuefolder.substring(0,7).replace(" ","_"));
133 				
134 				} else {
135 					
136 					startmenue_dir.addAttribute("Name",this.startmenuefolder.replace(" ","_"));
137 				}
138 				
139 			}
140 			
141 			this.feature = fragment.addElement("FeatureRef");
142 			feature.addAttribute("Id",this.featureid);					
143 			
144 			proceedDirectory(dir,this.srcdir);
145 			
146 			File destfile = new File(this.destdir,this.filename);
147 			
148 			handleOutput("Writing: "+destfile.getName());
149 			if (this.debug) handleOutput("File: "+destfile.getAbsolutePath());
150 			
151 			if (destfile.exists()) destfile.delete();
152 			
153 			OutputFormat format = OutputFormat.createPrettyPrint();
154 			XMLWriter writer = new XMLWriter( new FileWriter( destfile ), format );        
155 			writer.write( document );
156 			writer.close();
157 			
158 			if (debug) handleOutput("execute() finished");
159 			
160 		} catch (IOException e) {
161 
162 			throw new BuildException(e.getMessage(),e);
163 		}
164 		
165 	} // excecute()
166 	
167 	/**
168 	 * Function to proceed a directory. <br/>
169 	 * This Function operates recursively on a directory structure.
170 	 * 
171 	 * @param dir_elem The current &lt;Directory&gt; element of the fragmnet file 
172 	 * @param dir The current directory
173 	 */
174 	private void proceedDirectory(Element dir_elem, File dir) {
175 		
176 		if (debug) handleOutput("Dir: "+dir.getAbsolutePath());
177 		
178 		for (File f : dir.listFiles()) {
179 									
180 			if (f.isFile()) {
181 				
182 				boolean config = configs.contains(f);
183 				String compid = ('C' + idgen.next());
184 				
185 				if (debug) handleOutput("File [Config: "+config+"]: "+f.getAbsolutePath()+" Id: "+compid);
186 				
187 				
188 				Element comp_elem = dir_elem.addElement("Component");
189 				comp_elem.addAttribute("Id",compid);
190 				comp_elem.addAttribute("Guid",UUID.randomUUID().toString().toUpperCase());
191 				comp_elem.addAttribute("DiskId",this.diskid);
192 				
193 				Element file_elem = comp_elem.addElement("File");
194 				file_elem.addAttribute("Id",('F' + idgen.next()));
195 				file_elem.addAttribute("Name",namegen.next());
196 				file_elem.addAttribute("LongName",f.getName());
197 				file_elem.addAttribute("src",f.getAbsolutePath());
198 				file_elem.addAttribute("KeyPath","yes");
199 				file_elem.addAttribute("Vital","yes");
200 
201 				
202 				Element ref_elem = feature.addElement("ComponentRef");
203 				ref_elem.addAttribute("Id",compid);
204 
205 				
206 				if (config) {
207 					
208 					comp_elem.addAttribute("Permanent","yes");
209 					comp_elem.addAttribute("NeverOverwrite","yes");
210 					
211 					String compid_new = ('C' + idgen.next());
212 					
213 					Element comp_elem_new = dir_elem.addElement("Component");
214 					comp_elem_new.addAttribute("Id",compid_new);
215 					comp_elem_new.addAttribute("Guid",UUID.randomUUID().toString().toUpperCase());
216 					comp_elem_new.addAttribute("DiskId",this.diskid);
217 					
218 					Element file_elem_new = comp_elem_new.addElement("File");
219 					file_elem_new.addAttribute("Id",('F' + idgen.next()));
220 					file_elem_new.addAttribute("Name",namegen.next());
221 					file_elem_new.addAttribute("LongName",f.getName()+"-new");
222 					file_elem_new.addAttribute("src",f.getAbsolutePath());
223 					file_elem_new.addAttribute("KeyPath","yes");
224 					file_elem_new.addAttribute("Vital","yes");
225 
226 					Element ref_elem_new = feature.addElement("ComponentRef");
227 					ref_elem_new.addAttribute("Id",compid_new);
228 				}
229 				
230 				for (Shortcut s : this.desktopshortcuts) {
231 
232 					File shortcutfile = new File(this.srcdir,s.getFile());
233 										
234 					if (f.equals(shortcutfile)) {
235 					
236 						if (debug) handleOutput("Creating Desktop Shortcut ...");
237 						addShortcut(file_elem,s,this.idprefix + "DesktopFolder");
238 						
239 					} // if
240 					
241 				} // for
242 				
243 				for (Shortcut s : this.startmenueshortcuts) {
244 					
245 					File shortcutfile = new File(this.srcdir,s.getFile());
246 					
247 					if (f.equals(shortcutfile)) {
248 					
249 						if (debug) handleOutput("Creating Startmenue Shortcut ...");
250 						
251 						if (startmenuefolder != null) 
252 							addShortcut(file_elem,s,this.idprefix + "Start_Menue_Folder");
253 						else
254 							addShortcut(file_elem,s,this.idprefix + "ProgramMenuFolder");
255 							
256 					} // if
257 					
258 				} // for
259 				
260 			} // if
261 			
262 			if (f.isDirectory()) {
263 						
264 				String id = idgen.next();
265 				if (debug) handleOutput("Directory: "+f.getAbsolutePath()+" Id: "+id);
266 
267 				Element subdir_elem = dir_elem.addElement("Directory");
268 				subdir_elem.addAttribute("Id",('D' + id));
269 				subdir_elem.addAttribute("Name",namegen.next());
270 				subdir_elem.addAttribute("LongName",f.getName());
271 				
272 				proceedDirectory(subdir_elem,f);
273 				
274 			} // if
275 			
276 		} // for
277 
278 	} // proceedDirectory()
279 	
280 	/**
281 	 * Adds a Desktop / Startmenue shortcut for a file
282 	 * 
283 	 * @param file The target file of the shortcut
284 	 * @param s Shortcut object
285 	 * @param shortcut_dir Reference to the diretory to place the shortcut 
286 	 */
287 	private void addShortcut(Element file, Shortcut s, String shortcut_dir) {
288 	
289 		Element shortcut = file.addElement("Shortcut");
290 		shortcut.addAttribute("Id",('S' + idgen.next()));
291 		shortcut.addAttribute("Directory",shortcut_dir);
292 		shortcut.addAttribute("LongName",s.getName());
293 		shortcut.addAttribute("Name",namegen.next());
294 		
295 		if (s.getWorkingdir() != null) shortcut.addAttribute("WorkingDirectory",s.getWorkingdir());
296 		
297 		if (s.getArguments() != null) shortcut.addAttribute("Arguments",s.getArguments());
298 		
299  		if (s.getIcon() != null) {
300 		
301 			String iconid = ('I' + idgen.next());
302 			shortcut.addAttribute("Icon",iconid);
303 			
304 			File iconfile = new File(this.destdir,s.getIcon());
305 			if (debug) handleOutput("Icon File: "+iconfile.getAbsolutePath());
306 			
307 			Element icon = fragment.addElement("Icon");
308 			icon.addAttribute("Id",iconid);
309 			icon.addAttribute("src",iconfile.getAbsolutePath());
310 			
311 		} // if
312 				
313 	} // addShortcut()
314 	
315 	
316 	// -- [ Getter / Setter ] ------------------------------------------------------------
317 	
318 	/**
319 	 * Fileset with configuration files
320 	 */
321 	public Path createConfigfiles() {
322 		if (this.configfiles == null) this.configfiles = new Path(getProject());
323 		return this.configfiles.createPath();
324 	}
325 
326 	/**
327 	 * Shortcut to place on the desktop
328 	 */
329 	public void addDesktop(Shortcut s) {
330 		this.desktopshortcuts.add(s);
331 	}
332 	
333 	/**
334 	 * Shortcut to place in the startmenue
335 	 */
336 	public void addStartmenue(Shortcut s) {
337 		this.startmenueshortcuts.add(s);
338 	}
339 	
340 	/**
341 	 * Enable debug output
342 	 */
343 	public void setDebug(boolean debug) {
344 		this.debug = debug;
345 	}
346 
347 	/**
348 	 * The directory to create the file
349 	 */
350 	public void setDestdir(File destdir) {
351 		this.destdir = destdir;
352 	}
353 
354 	/**
355 	 * The name of the fragment file
356 	 */
357 	public void setFilename(String filename) {
358 		this.filename = filename;
359 	}
360 
361 	/**
362 	 * The id of the directory to reference
363 	 */
364 	public void setDirectoryid(String directoryid) {
365 		this.directoryid = directoryid;
366 	}
367 
368 	/**
369 	 * The id of the feature to reference
370 	 */
371 	public void setFeatureid(String featureid) {
372 		this.featureid = featureid;
373 	}
374 
375 	/**
376 	 * The id of the fragment
377 	 */
378 	public void setFragmentid(String fragmentid) {
379 		this.fragmentid = fragmentid;
380 	}
381 
382 	/**
383 	 * Directory containing the the files to include
384 	 */
385 	public void setSrcdir(File srcdir) {
386 		this.srcdir = srcdir;
387 	}
388 
389 	/**
390 	 * The diskid for the generated files
391 	 */
392 	public void setDiskid(String diskid) {
393 		this.diskid = diskid;
394 	}
395 
396 
397 	/**
398 	 * The folder inside the startmenue to place the shortcuts
399 	 */
400 	public void setStartmenuefolder(String startmenuefolder) {
401 		this.startmenuefolder = startmenuefolder;
402 	}
403 
404 	
405 	/**
406 	 * Prefix for generated IDs 
407 	 */
408 	public void setIdprefix(String idprefix) {
409 		this.idprefix = idprefix;
410 	}
411 
412 	
413 } // class