View Javadoc

1   package org.codehaus.mojo.javascript;
2   
3   /*
4    * Derivative Work
5    * Copyright 2010 SOFTEC sa. All rights reserved.
6    *
7    * Original Work
8    * Copyright 2001-2005 The Apache Software Foundation.
9    *
10   * Licensed under the Apache License, Version 2.0 (the "License");
11   * you may not use this file except in compliance with the License.
12   * You may obtain a copy of the License at
13   *
14   *      http://www.apache.org/licenses/LICENSE-2.0
15   *
16   * Unless required by applicable law or agreed to in writing, software
17   * distributed under the License is distributed on an "AS IS" BASIS,
18   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19   * See the License for the specific language governing permissions and
20   * limitations under the License.
21   */
22  
23  import java.io.File;
24  import java.io.FileReader;
25  import java.io.IOException;
26  import java.io.PrintWriter;
27  import java.util.Collections;
28  import java.util.HashSet;
29  import java.util.Iterator;
30  import java.util.List;
31  import java.util.Set;
32  
33  import org.apache.maven.artifact.DefaultArtifact;
34  import org.apache.maven.plugin.AbstractMojo;
35  import org.apache.maven.plugin.MojoExecutionException;
36  import org.apache.maven.plugin.MojoFailureException;
37  import org.apache.maven.project.MavenProject;
38  import org.codehaus.mojo.javascript.archive.JavascriptArtifactManager;
39  import org.codehaus.mojo.javascript.assembler.Assembler;
40  import org.codehaus.mojo.javascript.assembler.AssemblerReader;
41  import org.codehaus.mojo.javascript.assembler.AssemblerReaderManager;
42  import org.codehaus.mojo.javascript.assembler.Script;
43  import org.codehaus.plexus.archiver.ArchiverException;
44  import org.codehaus.plexus.util.DirectoryScanner;
45  import org.codehaus.plexus.util.FileUtils;
46  import org.codehaus.plexus.util.IOUtil;
47  
48  /**
49   * Goal which assemble javascript sources into the packaging directory. An
50   * optional assembler descriptor can be set to configure scripts to be merged.
51   * Other scripts are simply copied to the output directory.
52   *
53   * @goal compile
54   * @phase compile
55   * @requiresDependencyResolution compile
56   * @author <a href="mailto:nicolas@apache.org">Nicolas De Loof</a>
57   */
58  public class CompileMojo
59      extends AbstractMojo
60  {
61      /** default includes pattern */
62      protected static final String[] DEFAULT_INCLUDES = { "**/*.js" };
63  
64      /**
65       * The maven project.
66       *
67       * @parameter expression="${project}"
68       * @required
69       * @readonly
70       */
71      protected MavenProject project;
72  
73      /**
74       * Location of the source files.
75       *
76       * @parameter default-value="${basedir}/src/main/javascript"
77       */
78      protected File sourceDirectory;
79  
80      /**
81       * The output directory of the assembled js file.
82       *
83       * @parameter default-value="${project.build.outputDirectory}"
84       */
85      protected File outputDirectory;
86  
87      /**
88       * The folder where javascript dependencies are extracted and taken during assembling
89       *
90       * @parameter default-value="${project.build.directory}/javascript-dependency"
91       */
92      protected File depsDirectory;
93  
94      /**
95       * For dependencies, if true, create a folder named by the artifactId while unpacking
96       *
97       * @parameter
98       */
99      protected boolean useArtifactId;
100 
101     /**
102      * Exclusion pattern.
103      *
104      * @parameter
105      */
106     protected String[] excludes;
107 
108     /**
109      * Inclusion pattern.
110      *
111      * @parameter
112      */
113     protected String[] includes;
114 
115     /**
116      * @component
117      */
118     protected AssemblerReaderManager assemblerReaderManager;
119 
120     /**
121      * Descriptor for the strategy to assemble individual scripts sources into
122      * destination.
123      *
124      * @parameter default-value="${basedir}/src/assembler/${project.artifactId}.xml"
125      */
126     protected File descriptor;
127 
128     /**
129      * Descriptor file format (default or jsbuilder)
130      *
131      * @parameter
132      */
133     protected String descriptorFormat;
134 
135     /**
136      * @component
137      */
138     protected JavascriptArtifactManager javascriptArtifactManager;
139 
140     // Compile-time dependency count
141     protected int depsCount = 0;
142 
143     public void execute()
144         throws MojoExecutionException, MojoFailureException
145     {
146         if (outputDirectory == null) {
147             getLog().error("OutputDirectory is null");
148             throw new MojoExecutionException("outputDirectory must be specified");
149         } else {
150             getLog().debug("Creating outputDirectory " + outputDirectory);
151             outputDirectory.mkdirs();
152         }
153 
154         try
155         {
156             depsCount = getJavascriptArtifactManager().unpack( getProject(), DefaultArtifact.SCOPE_COMPILE,
157                 depsDirectory, useArtifactId );
158         }
159         catch ( ArchiverException e )
160         {
161             throw new MojoExecutionException( "Failed to unpack javascript dependencies", e );
162         }
163 
164         Set merged = assemble();
165 
166         copyUnmerged(merged);
167     }
168 
169     protected void copyUnmerged(Set merged) throws MojoExecutionException{
170         if ( includes == null )
171         {
172             includes = DEFAULT_INCLUDES;
173         }
174 
175         if( sourceDirectory.isDirectory() ) {
176             DirectoryScanner scanner = new DirectoryScanner();
177             scanner.setBasedir( sourceDirectory );
178             scanner.setExcludes( excludes );
179             scanner.addDefaultExcludes();
180 
181             scanner.setIncludes( includes );
182             scanner.scan();
183 
184             try
185             {
186                 String[] files = scanner.getIncludedFiles();
187                 for ( int i = 0; i < files.length; i++ )
188                 {
189                     String file = files[i];
190                     if ( merged.contains( file ) )
191                     {
192                         continue;
193                     }
194                     File source = new File( sourceDirectory, file );
195                     File dest = new File( outputDirectory, file );
196                     dest.getParentFile().mkdir();
197                     FileUtils.copyFile( source, dest );
198                 }
199             }
200             catch ( IOException e )
201             {
202                 throw new MojoExecutionException( "Failed to copy source files to " + outputDirectory,
203                     e );
204             }
205         }
206     }
207 
208     /**
209      * Honor the assembly rules to build merged scripts from individual ones.
210      *
211      * @return a set of all script merged, to be skiped from the target
212      * directory.
213      * @throws MojoExecutionException
214      */
215     protected Set assemble()
216         throws MojoExecutionException
217     {
218         if ( descriptor == null )
219         {
220             return Collections.EMPTY_SET;
221         }
222 
223         if ( !descriptor.exists() )
224         {
225             if ( descriptor.getName().equals( project.getArtifactId() + ".xml" ) )
226             {
227                 getLog().info( "No default assembler descriptor - just copy scripts" );
228                 return Collections.EMPTY_SET;
229             }
230             throw new MojoExecutionException( "The assembler descriptor does not exists : "
231                 + descriptor );
232         }
233 
234         if ( descriptorFormat == null )
235         {
236             descriptorFormat = "default";
237             if ( descriptor.getName().toLowerCase().endsWith( ".jsb" ) )
238             {
239                 descriptorFormat = "jsbuilder";
240             }
241         }
242 
243         Assembler assembler;
244         try
245         {
246             AssemblerReader reader = assemblerReaderManager.getAssemblerReader( descriptorFormat );
247             assembler = reader.getAssembler( descriptor );
248         }
249         catch ( Exception e )
250         {
251             throw new MojoExecutionException( "Failed to read the assembler descriptor "
252                 + descriptor.getAbsolutePath(), e );
253         }
254         return assemble( assembler );
255     }
256 
257     protected Set assemble( Assembler assembler )
258         throws MojoExecutionException
259     {
260         Set merged = new HashSet();
261 
262         DirectoryScanner scanner = null;
263         if( sourceDirectory.isDirectory() ) {
264             scanner = new DirectoryScanner();
265             scanner.setBasedir( sourceDirectory );
266             scanner.setExcludes( excludes );
267             scanner.addDefaultExcludes();
268         }
269 
270         DirectoryScanner depsScan = null;
271         if( depsCount > 0 ) {
272             depsScan = new DirectoryScanner();
273             depsScan.setBasedir( depsDirectory );
274             depsScan.setExcludes( excludes );
275             depsScan.addDefaultExcludes();
276         } else {
277             getLog().info( "No compile time dependency - just assembling local scripts" );
278         }
279 
280         if( scanner == null && depsScan == null ) {
281             throw new MojoExecutionException( "Nothing to compile or assemble ?" );
282         }
283 
284         for ( Iterator iterator = assembler.getScripts().iterator(); iterator.hasNext(); )
285         {
286             Script script = (Script) iterator.next();
287             String fileName = script.getFileName();
288             PrintWriter writer = null;
289             try
290             {
291                 File target = new File( outputDirectory, fileName );
292                 target.getParentFile().mkdirs();
293                 writer = new PrintWriter( target );
294 
295                 List scriptOrderedIncludes = script.getIncludes();
296                 for ( Iterator iter = scriptOrderedIncludes.iterator(); iter.hasNext(); )
297                 {
298                     String scriptInclude = (String) iter.next();
299 
300                     if ((scanner == null ||
301                         appendScriptFile(sourceDirectory, scanner, writer, scriptInclude, merged) < 1)
302                         && depsScan != null)
303                     {
304                         appendScriptFile(depsDirectory, depsScan, writer, scriptInclude, null);
305                     }
306                 }
307             }
308             catch ( IOException e )
309             {
310                 throw new MojoExecutionException( "Failed to write merged file " + fileName, e );
311             }
312             finally
313             {
314                 IOUtil.close( writer );
315             }
316         }
317         return merged;
318     }
319 
320     protected int appendScriptFile(File dir, DirectoryScanner scanner, PrintWriter writer, String scriptInclude, Set merged)
321         throws IOException
322     {
323         scanner.setIncludes( new String[] { scriptInclude } );
324         scanner.scan();
325 
326         String[] files = scanner.getIncludedFiles();
327         for ( int i = 0; i < files.length; i++ )
328         {
329             String file = files[i];
330             File source = new File( dir, file );
331             IOUtil.copy( new FileReader( source ), writer );
332             writer.println();
333             if( merged != null ) {
334                 merged.add( file );
335             }
336         }
337 
338         return files.length;
339     }
340 
341     /**
342      * @return the project
343      */
344     protected MavenProject getProject()
345     {
346         return project;
347     }
348 
349     /**
350      * @return the javascript artifact manager
351      */
352     protected JavascriptArtifactManager getJavascriptArtifactManager()
353     {
354         return javascriptArtifactManager;
355     }
356 }