View Javadoc

1   /*
2    * Copyright 2011 SOFTEC sa. All rights reserved.
3    *
4    * This source code is licensed under the Creative Commons
5    * Attribution-NonCommercial-NoDerivs 3.0 Luxembourg
6    * License.
7    *
8    * To view a copy of this license, visit
9    * http://creativecommons.org/licenses/by-nc-nd/3.0/lu/
10   * or send a letter to Creative Commons, 171 Second Street,
11   * Suite 300, San Francisco, California, 94105, USA.
12   */
13  
14  package org.codehaus.mojo.javascript;
15  
16  import org.apache.maven.artifact.DefaultArtifact;
17  import org.apache.maven.plugin.AbstractMojo;
18  import org.apache.maven.plugin.MojoExecutionException;
19  import org.apache.maven.plugin.MojoFailureException;
20  import org.apache.maven.project.MavenProject;
21  import org.codehaus.mojo.javascript.archive.JavascriptArtifactManager;
22  import org.codehaus.mojo.javascript.assembler.AssemblerReaderManager;
23  import org.codehaus.mojo.javascript.assembler.Assembler;
24  import org.codehaus.mojo.javascript.assembler.AssemblerReader;
25  import org.codehaus.mojo.javascript.assembler.AssemblerReaderManager;
26  import org.codehaus.mojo.javascript.assembler.Script;
27  import org.codehaus.mojo.javascript.titanium.FileStrip;
28  import org.codehaus.plexus.archiver.ArchiverException;
29  import org.codehaus.plexus.util.DirectoryScanner;
30  import org.codehaus.plexus.util.FileUtils;
31  import org.codehaus.plexus.util.IOUtil;
32  
33  import java.io.*;
34  import java.util.*;
35  
36  /**
37   * Goal that will place in a titanium build directory the file needed
38   * to create a titanium package.
39   *
40   * @phase compile
41   * @goal titanium-compile
42   * @plexus.component role-hint="titanium"
43   */
44  public class TitaniumCompileMojo extends CompileMojo {
45      private static Map<String, String> platformPatterns;
46  
47      static {
48          platformPatterns = new HashMap<String, String>();
49          platformPatterns.put("android", "**/android/**");
50          platformPatterns.put("iphone", "**/iphone/**");
51      }
52  
53      /**
54       * The platform for which the code should be compiled.
55       * android, iphone, ipad, universal
56       *
57       * @parameter expression="${platform}"
58       * @required
59       */
60      private String platform;
61  
62      /**
63       * The name of the script directory.
64       * <p>This parameter is optional it defaults to <code>platform-scripts</code></p>
65       * @parameter
66       */
67      private String scriptsDir;
68  
69      protected String getScriptsDir() {
70          if (scriptsDir == null) {
71              scriptsDir = platform + "-scripts";
72          }
73          return scriptsDir;
74      }
75  
76      private String getNormalizedPlatform() {
77          if (platform.equals("universal") || platform.equals("ipad")) {
78              return "iphone";
79          } else {
80              return platform;
81          }
82      }
83      /**
84       * The Titanium tiapp.xml configuration.
85       * If not specified a default tiapp.xml file will be generated
86       *
87       * @parameter
88       */
89      protected Tiapp tiapp;
90  
91      /**
92       * The folder for javascripts dependencies
93       *
94       * @parameter expression="${scripts}" default-value="lib"
95       */
96      protected String libsDirectory;
97  
98      protected File getPlatformOutputDirectory() {
99          return new File(outputDirectory, getScriptsDir());
100     }
101 
102 
103     /**
104      * Perform the titanium compilation phase.
105      * <p/>
106      * <ol>
107      * <li>Extract the dependencies in depsDirectory</li>
108      * <li>Copy the sourceDirectory files (using excludes and includes) to titaniumDirectory</li>
109      * <li>Move files located under "platform" folder outside of the platform folder.
110      * Based on the selected platform</li>
111      * <li>Assemble the files in one App.js file</li>
112      * </ol>
113      *
114      * @throws MojoExecutionException
115      * @throws MojoFailureException
116      */
117     public void execute() throws MojoExecutionException, MojoFailureException {
118         outputDirectory = getPlatformOutputDirectory();
119 
120         // Add the runtime dependencies to the lib folder
121         try
122         {
123             javascriptArtifactManager.unpack( project, DefaultArtifact.SCOPE_RUNTIME, new File(
124                 outputDirectory, libsDirectory ), useArtifactId );
125         }
126         catch ( ArchiverException e )
127         {
128             throw new MojoExecutionException( "Failed to unpack javascript dependencies", e );
129         }
130 
131         super.execute();
132     }
133 
134     private String[] getAllPlatformExcludes() {
135         List<String> result = new ArrayList<String>();
136         if (excludes != null) {
137             result.addAll(Arrays.asList(excludes));
138         }
139         for (Map.Entry<String, String> p : platformPatterns.entrySet()) {
140             result.add(p.getValue());
141         }
142         return result.toArray(new String[result.size()]);
143     }
144 
145     private String[] getPlatformExcludes() {
146         List<String> result = new ArrayList<String>();
147         if (excludes != null) {
148             result.addAll(Arrays.asList(excludes));
149         }
150         for (Map.Entry<String, String> p : platformPatterns.entrySet()) {
151             if (p.getKey().compareToIgnoreCase(getNormalizedPlatform()) != 0) {
152                 result.add(p.getValue());
153             }
154         }
155 
156         return result.toArray(new String[result.size()]);
157     }
158 
159     protected void copyUnmerged(Set merged) throws MojoExecutionException {
160         if (includes == null) {
161             includes = DEFAULT_INCLUDES;
162         }
163 
164         if (sourceDirectory.isDirectory()) {
165             DirectoryScanner scanner = new DirectoryScanner();
166             scanner.setBasedir(sourceDirectory);
167             scanner.setExcludes(getAllPlatformExcludes());
168             scanner.addDefaultExcludes();
169 
170             scanner.setIncludes(includes);
171             scanner.scan();
172 
173             try {
174                 String[] files = scanner.getIncludedFiles();
175                 List<String> genericFiles = new ArrayList<String>();
176 
177                 for (int i = 0; i < files.length; i++) {
178                     String file = files[i];
179                     if (merged.contains(file)) {
180                         continue;
181                     }
182                     genericFiles.add(file);
183                     File source = new File(sourceDirectory, file);
184                     File dest = new File(super.outputDirectory, file);
185                     getLog().debug("Copying " + source.getAbsolutePath() + " -> " + dest.getAbsolutePath());
186                     dest.getParentFile().mkdir();
187                     FileUtils.copyFile(source, dest);
188                 }
189 
190                 File platformSpecificFolder = new File(sourceDirectory, getNormalizedPlatform());
191                 if (platformSpecificFolder.exists() && platformSpecificFolder.isDirectory()) {
192                     scanner.setBasedir(platformSpecificFolder);
193                     scanner.setExcludes(excludes);
194                     scanner.scan();
195                     files = scanner.getIncludedFiles();
196                     for (int i = 0; i < files.length; i++) {
197                         String file = files[i];
198                         if (genericFiles.contains(file)) {
199                             File source = new File(platformSpecificFolder, file);
200                             File dest = new File(super.outputDirectory, file);
201                             getLog().debug("Overwriting with platform file " + source.getAbsolutePath() + " -> " + dest.getAbsolutePath());
202                             dest.getParentFile().mkdir();
203                             FileUtils.copyFile(source, dest);
204                         }
205                     }
206                 }
207             } catch (IOException e) {
208                 throw new MojoExecutionException("Failed to copy source files to " + outputDirectory,
209                         e);
210             }
211         }
212     }
213 
214     protected Set assemble(Assembler assembler)
215             throws MojoExecutionException {
216         Set merged = new HashSet();
217 
218         DirectoryScanner scanner = null;
219         if (sourceDirectory.isDirectory()) {
220             scanner = new DirectoryScanner();
221             scanner.setBasedir(sourceDirectory);
222             scanner.setExcludes(getAllPlatformExcludes());
223             scanner.addDefaultExcludes();
224         }
225 
226         DirectoryScanner depsScan = null;
227         if (depsCount > 0) {
228             depsScan = new DirectoryScanner();
229             depsScan.setBasedir(depsDirectory);
230             depsScan.setExcludes(excludes);
231             depsScan.addDefaultExcludes();
232         } else {
233             getLog().info("No compile time dependency - just assembling local scripts");
234         }
235 
236         if (scanner == null && depsScan == null) {
237             throw new MojoExecutionException("Nothing to compile or assemble ?");
238         }
239 
240         assembleScripts(assembler, scanner, depsScan, merged);
241         return merged;
242     }
243 
244     protected void assembleScripts(Assembler assembler,
245                                    DirectoryScanner scanner,
246                                    DirectoryScanner depsScan,
247                                    Set merged)
248             throws MojoExecutionException {
249         for (Iterator<Script> it = assembler.getScripts().iterator(); it.hasNext(); ) {
250             Script script = it.next();
251             String fileName = script.getFileName();
252             getLog().debug("Assembling Script: " + fileName);
253 
254             List scriptOrderedIncludes = script.getIncludes();
255             PrintWriter writer = null;
256             File target = new File(outputDirectory, fileName);
257             try {
258                 target.getParentFile().mkdirs();
259                 writer = new PrintWriter(target);
260 
261                 for (Iterator itInc = scriptOrderedIncludes.iterator(); itInc.hasNext(); ) {
262                     String includedScript = (String) itInc.next();
263 
264                     if ((scanner == null ||
265                             addScriptFile(scanner, includedScript, merged, writer) < 1)
266                             && depsScan != null) {
267                         appendScriptFile(depsDirectory, depsScan, writer, includedScript, null);
268                     }
269                 }
270             } catch (IOException e) {
271                 throw new MojoExecutionException("Failed to write merged file " + fileName, e);
272             } finally {
273                 IOUtil.close(writer);
274             }
275         }
276     }
277 
278     protected int addScriptFile(DirectoryScanner scanner, String fileName, Set merged, PrintWriter writer) throws IOException {
279         scanner.setIncludes(new String[]{fileName});
280         scanner.scan();
281 
282         String[] filesFound = scanner.getIncludedFiles();
283 
284         File baseDir = scanner.getBasedir();
285         File platformBaseDir = new File(baseDir, getNormalizedPlatform());
286 
287         String[] platformFilesFound = null;
288         if (platformBaseDir.exists() && platformBaseDir.isDirectory()) {
289             scanner.setBasedir(platformBaseDir);
290             scanner.setExcludes(excludes);
291             scanner.scan();
292 
293             platformFilesFound = scanner.getIncludedFiles();
294         }
295 
296         for (int i = 0; i < filesFound.length; i++) {
297             String genericFile = filesFound[i];
298             String platformFile = null;
299             File source = null;
300             if (platformFilesFound != null) {
301                 for (int j = 0; j < platformFilesFound.length && platformFile == null; j++) {
302                     String pFile = platformFilesFound[j];
303                     if (genericFile.equals(pFile)) {
304                         platformFile = pFile;
305                     }
306                 }
307             }
308 
309             if (platformFile != null) {
310                 source = new File(platformBaseDir, platformFile);
311                 getLog().debug(" Assembling platform file: " + source.getAbsolutePath());
312             } else {
313                 source = new File(baseDir, genericFile);
314                 getLog().debug(" Assembling generic file: " + source.getAbsolutePath());
315             }
316 
317             if (merged != null) {
318                 merged.add(genericFile);
319             }
320             IOUtil.copy(new FileReader(source), writer);
321             writer.println();
322         }
323 
324         scanner.setBasedir(baseDir);
325         scanner.setExcludes(getAllPlatformExcludes());
326 
327         return filesFound.length;
328     }
329 }