001    package org.apache.maven.tools.plugin.extractor;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *   http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import java.io.File;
023    import java.io.IOException;
024    import java.util.HashSet;
025    import java.util.List;
026    import java.util.Map;
027    import java.util.Set;
028    import java.util.TreeMap;
029    
030    import org.apache.maven.plugin.descriptor.InvalidPluginDescriptorException;
031    import org.apache.maven.plugin.descriptor.MojoDescriptor;
032    import org.apache.maven.plugin.descriptor.PluginDescriptor;
033    import org.apache.maven.project.MavenProject;
034    import org.apache.maven.tools.plugin.DefaultPluginToolsRequest;
035    import org.apache.maven.tools.plugin.PluginToolsRequest;
036    import org.codehaus.plexus.logging.AbstractLogEnabled;
037    import org.codehaus.plexus.util.DirectoryScanner;
038    import org.codehaus.plexus.util.FileUtils;
039    import org.codehaus.plexus.util.StringUtils;
040    
041    /**
042     * @author jdcasey
043     * @version $Id: AbstractScriptedMojoDescriptorExtractor.java 1212905 2011-12-10 22:31:48Z hboutemy $
044     */
045    public abstract class AbstractScriptedMojoDescriptorExtractor
046        extends AbstractLogEnabled
047        implements MojoDescriptorExtractor
048    {
049        /** {@inheritDoc} */
050        public List<MojoDescriptor> execute( MavenProject project, PluginDescriptor pluginDescriptor )
051            throws ExtractionException, InvalidPluginDescriptorException
052        {
053            return execute( new DefaultPluginToolsRequest( project, pluginDescriptor ) );
054        }
055        
056        /** {@inheritDoc} */
057        public List<MojoDescriptor> execute( PluginToolsRequest request )
058            throws ExtractionException, InvalidPluginDescriptorException
059        {
060            getLogger().debug( "Running: " + getClass().getName() );
061            String metadataExtension = getMetadataFileExtension( request );
062            String scriptExtension = getScriptFileExtension( request );
063            
064            MavenProject project = request.getProject();
065    
066            @SuppressWarnings( "unchecked" )
067            Map<String, Set<File>> scriptFilesKeyedByBasedir =
068                gatherFilesByBasedir( project.getBasedir(), project.getScriptSourceRoots(), scriptExtension, request );
069    
070            List<MojoDescriptor> mojoDescriptors;
071            if ( !StringUtils.isEmpty( metadataExtension ) )
072            {
073                @SuppressWarnings( "unchecked" )
074                Map<String, Set<File>> metadataFilesKeyedByBasedir =
075                    gatherFilesByBasedir( project.getBasedir(), project.getScriptSourceRoots(), metadataExtension,
076                                          request );
077    
078                mojoDescriptors = extractMojoDescriptorsFromMetadata( metadataFilesKeyedByBasedir, request );
079            }
080            else
081            {
082                mojoDescriptors = extractMojoDescriptors( scriptFilesKeyedByBasedir, request );
083            }
084    
085            copyScriptsToOutputDirectory( scriptFilesKeyedByBasedir, project.getBuild().getOutputDirectory(), request );
086    
087            return mojoDescriptors;
088        }
089    
090        /**
091         * @param scriptFilesKeyedByBasedir not null
092         * @param outputDirectory not null
093         * @throws ExtractionException if any
094         */
095        protected void copyScriptsToOutputDirectory( Map<String, Set<File>> scriptFilesKeyedByBasedir, String outputDirectory, PluginToolsRequest request )
096            throws ExtractionException
097        {
098            File outputDir = new File( outputDirectory );
099    
100            if ( !outputDir.exists() )
101            {
102                outputDir.mkdirs();
103            }
104    
105            for ( Map.Entry<String, Set<File>> entry : scriptFilesKeyedByBasedir.entrySet() )
106            {
107                File sourceDir = new File( entry.getKey() );
108    
109                Set<File> scripts = entry.getValue();
110    
111                for ( File scriptFile : scripts )
112                {
113                    String relativePath = scriptFile.getPath().substring( sourceDir.getPath().length() );
114    
115                    if ( relativePath.charAt( 0 ) == File.separatorChar )
116                    {
117                        relativePath = relativePath.substring( 1 );
118                    }
119    
120                    File outputFile = new File( outputDir, relativePath ).getAbsoluteFile();
121    
122                    if ( !outputFile.getParentFile().exists() )
123                    {
124                        outputFile.getParentFile().mkdirs();
125                    }
126    
127                    try
128                    {
129                        FileUtils.copyFile( scriptFile, outputFile );
130                    }
131                    catch ( IOException e )
132                    {
133                        throw new ExtractionException(
134                            "Cannot copy script file: " + scriptFile + " to output: " + outputFile, e );
135                    }
136                }
137            }
138        }
139    
140        /**
141         * @param basedir not null
142         * @param directories not null
143         * @param scriptFileExtension not null
144         * @return map with subdirs paths as key
145         */
146        protected Map<String, Set<File>> gatherFilesByBasedir( File basedir, List<String> directories, String scriptFileExtension, PluginToolsRequest request )
147        {
148            Map<String, Set<File>> sourcesByBasedir = new TreeMap<String, Set<File>>();
149    
150            for ( String resourceDir : directories )
151            {
152                Set<File> sources = new HashSet<File>();
153    
154                getLogger().debug( "Scanning script dir: " + resourceDir + " with extractor: " + getClass().getName() );
155                File dir = new File( resourceDir );
156                if ( !dir.isAbsolute() )
157                {
158                    dir = new File( basedir, resourceDir ).getAbsoluteFile();
159                }
160    
161                resourceDir = dir.getPath();
162    
163                if ( dir.exists() )
164                {
165                    DirectoryScanner scanner = new DirectoryScanner();
166    
167                    scanner.setBasedir( dir );
168                    scanner.addDefaultExcludes();
169                    scanner.setIncludes( new String[]{"**/*" + scriptFileExtension} );
170                    scanner.scan();
171    
172                    String[] relativePaths = scanner.getIncludedFiles();
173    
174                    for ( String relativePath : relativePaths )
175                    {
176                        File scriptFile = new File( dir, relativePath ).getAbsoluteFile();
177    
178                        if ( scriptFile.isFile() && relativePath.endsWith( scriptFileExtension ) )
179                        {
180                            sources.add( scriptFile );
181                        }
182                    }
183    
184                    sourcesByBasedir.put( resourceDir, sources );
185                }
186            }
187    
188            return sourcesByBasedir;
189        }
190    
191        /**
192         * Should be implemented in the sub classes.
193         *
194         * @param metadataFilesKeyedByBasedir could be null
195         * @param request The plugin request, never <code>null</code>.
196         * @return always null
197         * @throws ExtractionException if any
198         * @throws InvalidPluginDescriptorException if any
199         */
200        protected List<MojoDescriptor> extractMojoDescriptorsFromMetadata( Map<String, Set<File>> metadataFilesKeyedByBasedir,
201                                                           PluginToolsRequest request )
202            throws ExtractionException, InvalidPluginDescriptorException
203        {
204            return null;
205        }
206    
207        /**
208         * Should be implemented in the sub classes.
209         *
210         * @return always null
211         */
212        protected String getMetadataFileExtension( PluginToolsRequest request )
213        {
214            return null;
215        }
216    
217        /**
218         * Should be implemented in the sub classes.
219         *
220         * @param scriptFilesKeyedByBasedir could be null
221         * @param request The plugin request, never <code>null</code>.
222         * @return always null
223         * @throws ExtractionException if any
224         * @throws InvalidPluginDescriptorException if any
225         */
226        protected List<MojoDescriptor> extractMojoDescriptors( Map<String, Set<File>> scriptFilesKeyedByBasedir, PluginToolsRequest request )
227            throws ExtractionException, InvalidPluginDescriptorException
228        {
229            return null;
230        }
231    
232        /**
233         * @return the file extension like <code>.bsh</code> for BeanShell.
234         */
235        protected abstract String getScriptFileExtension( PluginToolsRequest request );
236    
237    }