001package org.apache.maven.script.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 org.apache.maven.artifact.Artifact;
023import org.apache.maven.artifact.DependencyResolutionRequiredException;
024import org.apache.maven.execution.MavenSession;
025import org.apache.maven.plugin.AbstractMojo;
026import org.apache.maven.plugin.ContextEnabled;
027import org.apache.maven.plugin.MojoExecution;
028import org.apache.maven.plugin.MojoExecutionException;
029import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
030import org.apache.maven.plugin.descriptor.PluginDescriptor;
031import org.apache.maven.project.MavenProject;
032import org.apache.maven.project.path.PathTranslator;
033import org.apache.tools.ant.Project;
034import org.apache.tools.ant.PropertyHelper;
035import org.apache.tools.ant.types.Path;
036import org.codehaus.plexus.archiver.ArchiverException;
037import org.codehaus.plexus.archiver.zip.ZipUnArchiver;
038import org.codehaus.plexus.component.MapOrientedComponent;
039import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
040import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
041import org.codehaus.plexus.component.factory.ant.AntComponentExecutionException;
042import org.codehaus.plexus.component.factory.ant.AntScriptInvoker;
043import org.codehaus.plexus.component.repository.ComponentRequirement;
044import org.codehaus.plexus.logging.LogEnabled;
045import org.codehaus.plexus.logging.Logger;
046import org.codehaus.plexus.util.StringUtils;
047
048import java.io.File;
049import java.util.ArrayList;
050import java.util.Collection;
051import java.util.HashMap;
052import java.util.List;
053import java.util.Map;
054
055/**
056 * 
057 */
058public class AntMojoWrapper
059    extends AbstractMojo
060    implements ContextEnabled, MapOrientedComponent, LogEnabled
061{
062
063    private Map<String, Object> pluginContext;
064    
065    private final AntScriptInvoker scriptInvoker;
066
067    private Project antProject;
068
069    private MavenProject mavenProject;
070
071    private MojoExecution mojoExecution;
072
073    private MavenSession session;
074    
075    private PathTranslator pathTranslator;
076
077    private Logger logger;
078    
079    private transient List<String> unconstructedParts = new ArrayList<>();
080
081    public AntMojoWrapper( AntScriptInvoker scriptInvoker )
082    {
083        this.scriptInvoker = scriptInvoker;
084    }
085
086    public void execute()
087        throws MojoExecutionException
088    {
089        if ( antProject == null )
090        {
091            antProject = scriptInvoker.getProject();
092        }
093        
094        Map<String, Object> allConfig = new HashMap<>();
095        if ( pluginContext != null && !pluginContext.isEmpty() )
096        {
097            allConfig.putAll( pluginContext );
098        }
099        
100        @SuppressWarnings( "unchecked" )
101        Map<String, PathTranslator> refs = scriptInvoker.getReferences();
102        if ( refs != null )
103        {
104            allConfig.putAll( refs );
105            
106            for ( Map.Entry<String, PathTranslator> entry : refs.entrySet() )
107            {
108                if ( entry.getKey().startsWith( PathTranslator.class.getName() ) )
109                {
110                    pathTranslator = entry.getValue();
111                }
112            }
113        }
114
115        mavenProject = (MavenProject) allConfig.get( "project" );
116        
117        mojoExecution = (MojoExecution) allConfig.get( "mojoExecution" );
118        
119        session = (MavenSession) allConfig.get( "session" );
120        
121        unpackFileBasedResources();
122
123        addClasspathReferences();
124        
125        if ( logger.isDebugEnabled() && !unconstructedParts.isEmpty() )
126        {
127            StringBuilder buffer = new StringBuilder();
128            
129            buffer.append( "The following standard Maven Ant-mojo support objects could not be created:\n\n" );
130            
131            for ( String part : unconstructedParts )
132            {
133                buffer.append( "\n-  " ).append( part );
134            }
135            
136            buffer.append( "\n\nMaven project, session, mojo-execution, or path-translation parameter "
137                + "information is " );
138            buffer.append( "\nmissing from this mojo's plugin descriptor." );
139            buffer.append( "\n\nPerhaps this Ant-based mojo depends on maven-script-ant < 2.1.0, " );
140            buffer.append( "or used maven-plugin-tools-ant < 2.2 during release?\n\n" );
141            
142            logger.debug( buffer.toString() );
143        }
144
145        try
146        {
147            scriptInvoker.invoke();
148        }
149        catch ( AntComponentExecutionException e )
150        {
151            throw new MojoExecutionException( "Failed to execute: " + e.getMessage(), e );
152        }
153        
154        unconstructedParts.clear();
155    }
156
157    public void setPluginContext( Map pluginContext )
158    {
159        this.pluginContext = pluginContext;
160    }
161
162    public Map getPluginContext()
163    {
164        return pluginContext;
165    }
166
167    public void addComponentRequirement( ComponentRequirement requirementDescriptor, Object requirementValue )
168        throws ComponentConfigurationException
169    {
170        scriptInvoker.addComponentRequirement( requirementDescriptor, requirementValue );
171    }
172
173    public void setComponentConfiguration( Map componentConfiguration )
174        throws ComponentConfigurationException
175    {
176        scriptInvoker.setComponentConfiguration( componentConfiguration );
177        antProject = scriptInvoker.getProject();
178    }
179
180    private void unpackFileBasedResources()
181        throws MojoExecutionException
182    {
183        if ( mojoExecution == null || mavenProject == null )
184        {
185            unconstructedParts.add( "Unpacked Ant build scripts (in Maven build directory)." );
186            
187            return;
188        }
189        
190        // What we need to write out any resources in the plugin to the target directory of the
191        // mavenProject using the Ant-based plugin:
192        //
193        // 1. Need a reference to the plugin JAR itself
194        // 2. Need a reference to the ${basedir} of the mavenProject
195
196        PluginDescriptor pluginDescriptor = mojoExecution.getMojoDescriptor().getPluginDescriptor();
197        
198        File pluginJar = pluginDescriptor.getPluginArtifact().getFile();
199
200        String resourcesPath = pluginDescriptor.getArtifactId();
201
202        File outputDirectory = new File( mavenProject.getBuild().getDirectory() );
203
204        try
205        {
206            ZipUnArchiver ua = new ZipUnArchiver( pluginJar );
207            ua.enableLogging( logger );
208
209            ua.extract( resourcesPath, outputDirectory );
210        }
211        catch ( ArchiverException e )
212        {
213            throw new MojoExecutionException( "Error extracting resources from your Ant-based plugin.", e );
214        }
215    }
216
217    private void addClasspathReferences()
218        throws MojoExecutionException
219    {
220        try
221        {
222            if ( mavenProject != null && session != null && pathTranslator != null )
223            {
224                ExpressionEvaluator exprEvaluator =
225                    new PluginParameterExpressionEvaluator( session, mojoExecution, pathTranslator, logger,
226                                                            mavenProject, mavenProject.getProperties() );
227                
228                PropertyHelper propertyHelper = PropertyHelper.getPropertyHelper( antProject );
229                propertyHelper.setNext( new AntPropertyHelper( exprEvaluator, mavenProject.getArtifacts(), getLog() ) );
230            }
231            else
232            {
233                unconstructedParts.add( "Maven parameter expression evaluator for Ant properties." );
234            }
235
236            @SuppressWarnings( "unchecked" )
237            Map<String, Object> references = scriptInvoker.getReferences();
238
239            if ( mavenProject != null )
240            {
241
242                // Compile classpath
243                Path p = new Path( antProject );
244
245                p.setPath( StringUtils.join( mavenProject.getCompileClasspathElements().iterator(),
246                                             File.pathSeparator ) );
247
248                /* maven.dependency.classpath it's deprecated as it's equal to maven.compile.classpath */
249                references.put( "maven.dependency.classpath", p );
250                antProject.addReference( "maven.dependency.classpath", p );
251                
252                references.put( "maven.compile.classpath", p );
253                antProject.addReference( "maven.compile.classpath", p );
254
255                // Runtime classpath
256                p = new Path( antProject );
257
258                p.setPath( StringUtils.join( mavenProject.getRuntimeClasspathElements().iterator(),
259                                             File.pathSeparator ) );
260
261                references.put( "maven.runtime.classpath", p );
262                antProject.addReference( "maven.runtime.classpath", p );
263
264                // Test classpath
265                p = new Path( antProject );
266
267                p.setPath( StringUtils.join( mavenProject.getTestClasspathElements().iterator(),
268                                             File.pathSeparator ) );
269
270                references.put( "maven.test.classpath", p );
271                antProject.addReference( "maven.test.classpath", p );
272
273            }
274            else
275            {
276                unconstructedParts.add( "Maven standard project-based classpath references." );
277            }
278            
279            if ( mojoExecution != null )
280            {
281                // Plugin dependency classpath
282                Path p =
283                    getPathFromArtifacts( mojoExecution.getMojoDescriptor().getPluginDescriptor().getArtifacts(),
284                                          antProject );
285                
286                references.put( "maven.plugin.classpath", p );
287                antProject.addReference( "maven.plugin.classpath", p );
288            }
289            else
290            {
291                unconstructedParts.add( "Maven standard plugin-based classpath references." );
292            }
293        }
294        catch ( DependencyResolutionRequiredException e )
295        {
296            throw new MojoExecutionException( "Error creating classpath references for Ant-based plugin scripts.", e );
297        }
298    }
299
300    public Path getPathFromArtifacts( Collection<Artifact> artifacts, Project antProject )
301        throws DependencyResolutionRequiredException
302    {
303        List<String> list = new ArrayList<>( artifacts.size() );
304
305        for ( Artifact a : artifacts )
306        {
307            File file = a.getFile();
308
309            if ( file == null )
310            {
311                throw new DependencyResolutionRequiredException( a );
312            }
313
314            list.add( file.getPath() );
315        }
316
317        Path p = new Path( antProject );
318
319        p.setPath( StringUtils.join( list.iterator(), File.pathSeparator ) );
320
321        return p;
322    }
323
324    public Project getAntProject()
325    {
326        return antProject;
327    }
328
329    public void setAntProject( Project antProject )
330    {
331        this.antProject = antProject;
332    }
333
334    public MavenProject getMavenProject()
335    {
336        return mavenProject;
337    }
338
339    public void setMavenProject( MavenProject mavenProject )
340    {
341        this.mavenProject = mavenProject;
342    }
343
344    public MojoExecution getMojoExecution()
345    {
346        return mojoExecution;
347    }
348
349    public void setMojoExecution( MojoExecution mojoExecution )
350    {
351        this.mojoExecution = mojoExecution;
352    }
353
354    public MavenSession getSession()
355    {
356        return session;
357    }
358
359    public void setSession( MavenSession session )
360    {
361        this.session = session;
362    }
363
364    public PathTranslator getPathTranslator()
365    {
366        return pathTranslator;
367    }
368
369    public void setPathTranslator( PathTranslator pathTranslator )
370    {
371        this.pathTranslator = pathTranslator;
372    }
373
374    public AntScriptInvoker getScriptInvoker()
375    {
376        return scriptInvoker;
377    }
378
379    public void enableLogging( Logger logger )
380    {
381        this.logger = logger;
382    }
383}