| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| package org.apache.ant.dotnet.wix; |
| |
| import org.apache.ant.dotnet.DotNetExecTask; |
| import org.apache.ant.dotnet.build.AbstractBuildTask; |
| import org.apache.tools.ant.BuildException; |
| import org.apache.tools.ant.DirectoryScanner; |
| import org.apache.tools.ant.Task; |
| import org.apache.tools.ant.types.Commandline; |
| import org.apache.tools.ant.types.EnumeratedAttribute; |
| import org.apache.tools.ant.types.FileSet; |
| |
| import java.io.File; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| |
| /** |
| * Task to run the WiX utility to create MSI files from an XML description. |
| * |
| * @see http://sf.net/projects/wix |
| */ |
| public class WixTask extends Task { |
| |
| /** |
| * The vm attribute - if given. |
| */ |
| private String vm; |
| |
| /** |
| * The source files. |
| */ |
| private ArrayList sources = new ArrayList(); |
| |
| /** |
| * Additional source files (include files in the case of candle, |
| * or media/files/whatever in the case of light). |
| */ |
| private ArrayList moreSources = new ArrayList(); |
| |
| /** |
| * A single source file. |
| */ |
| private File source; |
| |
| /** |
| * The target file. |
| */ |
| private File target; |
| |
| /** |
| * What to do. |
| */ |
| private Mode mode; |
| |
| /** |
| * Where is WiX installed? |
| */ |
| private File wixHome = null; |
| |
| /** |
| * Where to place the generated .wixobj files. |
| */ |
| private File wixobjDestDir = null; |
| |
| /** |
| * addtional command line arguments for candle. |
| */ |
| private Commandline candleCmdl = new Commandline(); |
| |
| /** |
| * list of parameters for the preprocessor. |
| */ |
| private ArrayList candleParameters = new ArrayList(); |
| |
| /** |
| * addtional command line arguments for light. |
| */ |
| private Commandline lightCmdl = new Commandline(); |
| |
| /** |
| * list of parameters for the "compiler". |
| */ |
| private ArrayList lightParameters = new ArrayList(); |
| |
| /** |
| * Whether to use lit.exe rather than light.exe. |
| */ |
| private boolean useLit = false; |
| |
| public WixTask() { |
| super(); |
| } |
| |
| /** |
| * Set the name of the executable for the virtual machine. |
| * |
| * @param value the name of the executable for the virtual machine |
| */ |
| public void setVm(String value) { |
| this.vm = value; |
| } |
| |
| /** |
| * The main source file. |
| * |
| * <p><code>candle</code> may include more files than this one, |
| * the main source is the one passed on the command line.</p> |
| * |
| * @param File object of the main source file. |
| */ |
| public void setSource(File f) { |
| source = f; |
| } |
| |
| /** |
| * The main target file. |
| * |
| * @param File object of the main target file. |
| */ |
| public void setTarget(File f) { |
| target = f; |
| } |
| |
| /** |
| * A set of source files. |
| */ |
| public void addSources(FileSet fs) { |
| sources.add(fs); |
| } |
| |
| /** |
| * A set of additional source files (include files in the case of |
| * candle, or media/files/whatever in the case of light). |
| * |
| * <p>Unlike the files specified as sources, these will not be |
| * passed on the command line, they only help Ant to determine |
| * whether the target is out-of-date.</p> |
| */ |
| public void addMoreSources(FileSet fs) { |
| moreSources.add(fs); |
| } |
| |
| /** |
| * Sets the installation directory of WiX. |
| * |
| * <p>If omitted, Ant will assume that WiX's executables can be |
| * found on the PATH.</p> |
| */ |
| public void setWixHome(File f) { |
| wixHome = f; |
| } |
| |
| /** |
| * Whether to run candle, light or both. |
| */ |
| public void setMode(Mode m) { |
| mode = m; |
| } |
| |
| /** |
| * Sets the destination directory for wixobj files generated by candle. |
| * |
| * <p>Let's candle decide and assumes they'll be created in the |
| * current working directory.</p> |
| */ |
| public void setWixobjDestDir(File f) { |
| wixobjDestDir = f; |
| } |
| |
| /** |
| * A parameter to pass to candle.exe. |
| */ |
| public final void addCandleParameter(AbstractBuildTask.Property t) { |
| candleParameters.add(t); |
| } |
| |
| /** |
| * A parameter to pass to light.exe. |
| */ |
| public final void addLightParameter(AbstractBuildTask.Property t) { |
| lightParameters.add(t); |
| } |
| |
| /** |
| * Adds a command-line argument for light.exe. |
| * |
| * @return new command line argument created. |
| */ |
| public Commandline.Argument createLightArg() { |
| return lightCmdl.createArgument(); |
| } |
| |
| /** |
| * Adds a command-line argument for candle.exe. |
| * |
| * @return new command line argument created. |
| */ |
| public Commandline.Argument createCandleArg() { |
| return candleCmdl.createArgument(); |
| } |
| |
| /** |
| * Instructs the task to use lit.exe rather than light.exe as "compiler". |
| * |
| * @since .NET Antlib 1.1 |
| */ |
| public void setUseLit(boolean b) { |
| useLit = b; |
| } |
| |
| public void execute() { |
| if (source == null && sources.size() == 0) { |
| throw new BuildException("You must specify at least one source" |
| + " file."); |
| } |
| |
| if (source != null && !source.exists()) { |
| throw new BuildException("Source file " + source |
| + " doesn't exist."); |
| } |
| |
| String m = Mode.BOTH; |
| if (mode != null) { |
| m = mode.getValue(); |
| } |
| |
| if (target == null && !m.equals(Mode.CANDLE)) { |
| throw new BuildException("You must specify the target if you want" |
| + " to run light."); |
| } |
| |
| Collection lightSources = null; |
| if (!m.equals(Mode.LIGHT)) { |
| lightSources = doCandle(); |
| } else { |
| lightSources = new HashSet(); |
| if (source != null) { |
| lightSources.add(source); |
| } |
| if (sources.size() > 0) { |
| lightSources.addAll(grabFiles(sources)); |
| } |
| } |
| |
| if (!m.equals(Mode.CANDLE)) { |
| Collection moreLightSources = Collections.EMPTY_SET; |
| if (moreSources.size() > 0) { |
| moreLightSources = grabFiles(moreSources); |
| } |
| doLight(lightSources, moreLightSources); |
| } |
| } |
| |
| /** |
| * Invoke candle on all sources that are newer than their targets. |
| * |
| * @return a set of File objects pointing to the generated files. |
| */ |
| private Collection doCandle() { |
| Set s = new HashSet(); |
| if (source != null) { |
| s.add(source); |
| } |
| if (sources != null) { |
| s.addAll(grabFiles(sources)); |
| } |
| Set ms = new HashSet(); |
| if (moreSources != null) { |
| ms.addAll(grabFiles(moreSources)); |
| } |
| |
| Set toProcess = new HashSet(); |
| Set generatedTargets = new HashSet(); |
| Iterator iter = s.iterator(); |
| while (iter.hasNext()) { |
| File thisSource = (File) iter.next(); |
| File t = getTarget(thisSource); |
| generatedTargets.add(t); |
| if (isOutOfDate(t, thisSource, ms)) { |
| toProcess.add(thisSource); |
| } |
| } |
| if (toProcess.size() != 0) { |
| runCandle(toProcess); |
| return generatedTargets; |
| } |
| return Collections.EMPTY_SET; |
| } |
| |
| /** |
| * Invoke light on all sources that are newer than their targets. |
| */ |
| private void doLight(Collection lightSources, |
| Collection moreLightSources) { |
| Set tmp = new HashSet(lightSources); |
| tmp.addAll(moreLightSources); |
| if (isOutOfDate(target, tmp)) { |
| runLight(lightSources); |
| } |
| } |
| |
| /** |
| * Run candle passing all files of the collection on the command line. |
| */ |
| private void runCandle(Collection s) { |
| run(wixExecutable("candle.exe"), s, null, wixobjDestDir, |
| candleParameters, candleCmdl); |
| } |
| |
| /** |
| * Run light passing all files of the collection on the command line. |
| */ |
| private void runLight(Collection s) { |
| run(wixExecutable(useLit ? "lit.exe" : "light.exe"), s, target, null, |
| lightParameters, lightCmdl); |
| } |
| |
| /** |
| * returns an absolute path for the given executable if wixHome |
| * has been specified, the given name otherwise. |
| */ |
| private String wixExecutable(String name) { |
| return wixHome == null ? name |
| : new File(wixHome, name).getAbsolutePath(); |
| } |
| |
| /** |
| * Runs the specified command passing all files of the collection |
| * on the command line - potentially adding an /out parameter. |
| */ |
| private void run(String executable, Collection s, File target, |
| File runInDir, Collection params, Commandline cmdl) { |
| DotNetExecTask exec = DotNetExecTask.getTask(this, vm, |
| executable, null); |
| if (runInDir != null) { |
| exec.setDir(runInDir); |
| } |
| |
| exec.setFailonerror(true); |
| exec.setTaskType("wix"); |
| |
| exec.createArg().setValue("/nologo"); |
| |
| Iterator iter = s.iterator(); |
| while (iter.hasNext()) { |
| File f = (File) iter.next(); |
| exec.createArg().setValue(f.getAbsolutePath()); |
| } |
| if (target != null) { |
| exec.createArg().setValue("/out"); |
| exec.createArg().setValue(target.getAbsolutePath()); |
| } |
| |
| iter = params.iterator(); |
| while (iter.hasNext()) { |
| AbstractBuildTask.Property p = |
| (AbstractBuildTask.Property) iter.next(); |
| exec.createArg().setValue("-d" + p.getName() + "=" + p.getValue()); |
| } |
| String[] extraArgs = cmdl.getArguments(); |
| for (int i = 0; i < extraArgs.length; i++) { |
| exec.createArg().setValue(extraArgs[i]); |
| } |
| |
| exec.execute(); |
| } |
| |
| /** |
| * Is t older than s or any of the files in list? |
| */ |
| private boolean isOutOfDate(File t, File s, Collection l) { |
| return t.lastModified() < s.lastModified() || isOutOfDate(t, l); |
| } |
| |
| /** |
| * Is t older than any of the files in list? |
| */ |
| private boolean isOutOfDate(File t, Collection l) { |
| Iterator iter = l.iterator(); |
| while (iter.hasNext()) { |
| File f = (File) iter.next(); |
| if (t.lastModified() < f.lastModified()) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Turn the fileset collection into a list of Files. |
| */ |
| private Collection grabFiles(Collection s) { |
| Set r = new HashSet(); |
| Iterator iter = s.iterator(); |
| while (iter.hasNext()) { |
| FileSet fs = (FileSet) iter.next(); |
| DirectoryScanner ds = fs.getDirectoryScanner(getProject()); |
| String[] f = ds.getIncludedFiles(); |
| File base = fs.getDir(getProject()); |
| for (int i = 0; i < f.length; i++) { |
| r.add(new File(base, f[i])); |
| } |
| } |
| return r; |
| } |
| |
| /** |
| * Generates the name of a candle target from the source file. |
| * |
| * <p>Simply chops of the extension, adds .wixobj and calculates |
| * the absolute path based on wixobjDestDir.</p> |
| */ |
| private File getTarget(File s) { |
| String name = s.getName(); |
| int dot = name.lastIndexOf("."); |
| if (dot > -1) { |
| name = name.substring(0, dot) + ".wixobj"; |
| } else { |
| name = name + ".wixobj"; |
| } |
| |
| return wixobjDestDir == null |
| ? new File(name) : new File(wixobjDestDir, name); |
| } |
| |
| public static class Mode extends EnumeratedAttribute { |
| private final static String CANDLE = "candle"; |
| private final static String LIGHT = "light"; |
| private final static String BOTH = "both"; |
| |
| public Mode() { |
| super(); |
| } |
| |
| public String[] getValues() { |
| return new String[] {CANDLE, LIGHT, BOTH,}; |
| } |
| } |
| } |