001package org.apache.maven.tools.plugin.extractor.ant;
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
022import java.io.File;
023import java.util.ArrayList;
024import java.util.HashMap;
025import java.util.List;
026import java.util.Map;
027import java.util.Set;
028
029import org.apache.maven.plugin.descriptor.InvalidPluginDescriptorException;
030import org.apache.maven.plugin.descriptor.MojoDescriptor;
031import org.apache.maven.plugin.descriptor.Parameter;
032import org.apache.maven.project.MavenProject;
033import org.apache.maven.project.path.PathTranslator;
034import org.apache.maven.tools.plugin.PluginToolsRequest;
035import org.apache.maven.tools.plugin.extractor.AbstractScriptedMojoDescriptorExtractor;
036import org.apache.maven.tools.plugin.extractor.ExtractionException;
037import org.apache.maven.tools.plugin.extractor.MojoDescriptorExtractor;
038import org.apache.maven.tools.plugin.extractor.model.PluginMetadataParseException;
039import org.apache.maven.tools.plugin.extractor.model.PluginMetadataParser;
040import org.codehaus.plexus.component.annotations.Component;
041import org.codehaus.plexus.component.repository.ComponentRequirement;
042import org.codehaus.plexus.util.StringUtils;
043
044/**
045 * Extracts Mojo descriptors from <a href="http://ant.apache.org">Ant</a> sources.
046 *
047 */
048@Component( role = MojoDescriptorExtractor.class, hint = "ant" )
049public class AntMojoDescriptorExtractor
050    extends AbstractScriptedMojoDescriptorExtractor
051    implements MojoDescriptorExtractor
052{
053    /** Default metadata file extension */
054    private static final String METADATA_FILE_EXTENSION = ".mojos.xml";
055
056    /** Default Ant build file extension */
057    private static final String SCRIPT_FILE_EXTENSION = ".build.xml";
058    
059    /** {@inheritDoc} */
060    protected List<MojoDescriptor> extractMojoDescriptorsFromMetadata(
061                                                                  Map<String, Set<File>> metadataFilesKeyedByBasedir,
062                                                                  PluginToolsRequest request )
063        throws ExtractionException, InvalidPluginDescriptorException
064    {
065        List<MojoDescriptor> descriptors = new ArrayList<>();
066
067        PluginMetadataParser parser = new PluginMetadataParser();
068
069        for ( Map.Entry<String, Set<File>> entry : metadataFilesKeyedByBasedir.entrySet() )
070        {
071            String basedir = entry.getKey();
072            Set<File> metadataFiles = entry.getValue();
073
074            for ( File metadataFile : metadataFiles )
075            {
076                String basename = metadataFile.getName();
077                basename = basename.substring( 0, basename.length() - METADATA_FILE_EXTENSION.length() );
078
079                File scriptFile = new File( metadataFile.getParentFile(), basename + SCRIPT_FILE_EXTENSION );
080
081                if ( !scriptFile.exists() )
082                {
083                    throw new InvalidPluginDescriptorException(
084                        "Found orphaned plugin metadata file: " + metadataFile );
085                }
086
087                String relativePath = scriptFile.getPath().substring( basedir.length() ).replace( '\\', '/' );
088                
089                if ( relativePath.startsWith( "/" ) )
090                {
091                    relativePath = relativePath.substring( 1 );
092                }
093
094                try
095                {
096                    Set<MojoDescriptor> mojoDescriptors = parser.parseMojoDescriptors( metadataFile );
097
098                    for ( MojoDescriptor descriptor : mojoDescriptors )
099                    {
100                        @SuppressWarnings( "unchecked" )
101                        Map<String, ?> paramMap = descriptor.getParameterMap();
102
103                        if ( !paramMap.containsKey( "basedir" ) )
104                        {
105                            Parameter param = new Parameter();
106                            param.setName( "basedir" );
107                            param.setAlias( "ant.basedir" );
108                            param.setExpression( "${antBasedir}" );
109                            param.setDefaultValue( "${basedir}" );
110                            param.setType( "java.io.File" );
111                            param.setDescription( "The base directory from which to execute the Ant script." );
112                            param.setEditable( true );
113                            param.setRequired( true );
114
115                            descriptor.addParameter( param );
116                        }
117
118                        if ( !paramMap.containsKey( "antMessageLevel" ) )
119                        {
120                            Parameter param = new Parameter();
121                            param.setName( "messageLevel" );
122                            param.setAlias( "ant.messageLevel" );
123                            param.setExpression( "${antMessageLevel}" );
124                            param.setDefaultValue( "info" );
125                            param.setType( "java.lang.String" );
126                            param.setDescription( "The message-level used to tune the verbosity of Ant logging." );
127                            param.setEditable( true );
128                            param.setRequired( false );
129
130                            descriptor.addParameter( param );
131                        }
132                        
133                        if ( !paramMap.containsKey( "project" ) )
134                        {
135                            Parameter param = new Parameter();
136                            param.setName( "project" );
137                            param.setDefaultValue( "${project}" );
138                            param.setType( MavenProject.class.getName() );
139                            param.setDescription( "The current MavenProject instance, which contains classpath "
140                                + "elements." );
141                            param.setEditable( false );
142                            param.setRequired( true );
143
144                            descriptor.addParameter( param );
145                        }
146
147                        if ( !paramMap.containsKey( "session" ) )
148                        {
149                            Parameter param = new Parameter();
150                            param.setName( "session" );
151                            param.setDefaultValue( "${session}" );
152                            param.setType( "org.apache.maven.execution.MavenSession" );
153                            param.setDescription( "The current MavenSession instance, which is used for "
154                                + "plugin-style expression resolution." );
155                            param.setEditable( false );
156                            param.setRequired( true );
157
158                            descriptor.addParameter( param );
159                        }
160
161                        if ( !paramMap.containsKey( "mojoExecution" ) )
162                        {
163                            Parameter param = new Parameter();
164                            param.setName( "mojoExecution" );
165                            param.setDefaultValue( "${mojoExecution}" );
166                            param.setType( "org.apache.maven.plugin.MojoExecution" );
167                            param.setDescription( "The current Maven MojoExecution instance, which contains "
168                                + "information about the mojo currently executing." );
169                            param.setEditable( false );
170                            param.setRequired( true );
171
172                            descriptor.addParameter( param );
173                        }
174                        
175                        @SuppressWarnings( "unchecked" )
176                        List<ComponentRequirement> requirements = descriptor.getRequirements();
177                        Map<String, ComponentRequirement> reqMap = new HashMap<>();
178
179                        if ( requirements != null )
180                        {
181                            for ( ComponentRequirement req : requirements )
182                            {
183                                reqMap.put( req.getRole(), req );
184                            }
185                        }
186                        
187                        if ( !reqMap.containsKey( PathTranslator.class.getName() ) )
188                        {
189                            ComponentRequirement req = new ComponentRequirement();
190                            req.setRole( PathTranslator.class.getName() );
191                            
192                            descriptor.addRequirement( req );
193                        }
194
195                        String implementation = relativePath;
196
197                        String dImpl = descriptor.getImplementation();
198                        if ( StringUtils.isNotEmpty( dImpl ) )
199                        {
200                            if ( PluginMetadataParser.IMPL_BASE_PLACEHOLDER.equals( dImpl ) )
201                            {
202                                implementation = relativePath;
203                            }
204                            else
205                            {
206                                implementation =
207                                    relativePath
208                                        + dImpl.substring( PluginMetadataParser.IMPL_BASE_PLACEHOLDER.length() );
209                            }
210                        }
211
212                        descriptor.setImplementation( implementation );
213
214                        descriptor.setLanguage( "ant-mojo" );
215                        descriptor.setComponentComposer( "map-oriented" );
216                        descriptor.setComponentConfigurator( "map-oriented" );
217
218                        descriptor.setPluginDescriptor( request.getPluginDescriptor() );
219
220                        descriptors.add( descriptor );
221                    }
222                }
223                catch ( PluginMetadataParseException e )
224                {
225                    throw new ExtractionException( "Error extracting mojo descriptor from script: " + metadataFile, e );
226                }
227            }
228        }
229
230        return descriptors;
231    }
232
233    /** {@inheritDoc} */
234    protected String getScriptFileExtension( PluginToolsRequest request )
235    {
236        return SCRIPT_FILE_EXTENSION;
237    }
238
239    /** {@inheritDoc} */
240    protected String getMetadataFileExtension( PluginToolsRequest request )
241    {
242        return METADATA_FILE_EXTENSION;
243    }
244}