View Javadoc

1   package org.apache.maven.artifact.ant;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.artifact.Artifact;
23  import org.apache.maven.artifact.factory.ArtifactFactory;
24  import org.apache.maven.artifact.manager.WagonManager;
25  import org.apache.maven.artifact.repository.ArtifactRepository;
26  import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
27  import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
28  import org.apache.maven.artifact.repository.DefaultArtifactRepository;
29  import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
30  import org.apache.maven.profiles.DefaultProfileManager;
31  import org.apache.maven.profiles.ProfileManager;
32  import org.apache.maven.project.MavenProject;
33  import org.apache.maven.project.MavenProjectBuilder;
34  import org.apache.maven.project.ProjectBuildingException;
35  import org.apache.maven.settings.Mirror;
36  import org.apache.maven.settings.RuntimeInfo;
37  import org.apache.maven.settings.Server;
38  import org.apache.maven.settings.Settings;
39  import org.apache.maven.settings.SettingsUtils;
40  import org.apache.maven.settings.TrackableBase;
41  import org.apache.maven.settings.io.xpp3.SettingsXpp3Reader;
42  import org.apache.maven.usability.diagnostics.ErrorDiagnostics;
43  import org.apache.maven.wagon.Wagon;
44  import org.apache.tools.ant.BuildException;
45  import org.apache.tools.ant.Project;
46  import org.apache.tools.ant.Task;
47  import org.apache.tools.ant.taskdefs.Execute;
48  import org.codehaus.classworlds.ClassWorld;
49  import org.codehaus.classworlds.DuplicateRealmException;
50  import org.codehaus.plexus.PlexusContainer;
51  import org.codehaus.plexus.PlexusContainerException;
52  import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
53  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
54  import org.codehaus.plexus.embed.Embedder;
55  import org.codehaus.plexus.util.IOUtil;
56  import org.codehaus.plexus.util.ReaderFactory;
57  import org.codehaus.plexus.util.StringUtils;
58  import org.codehaus.plexus.util.interpolation.EnvarBasedValueSource;
59  import org.codehaus.plexus.util.interpolation.RegexBasedInterpolator;
60  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
61  
62  import java.io.File;
63  import java.io.IOException;
64  import java.io.Reader;
65  import java.io.StringReader;
66  import java.io.StringWriter;
67  import java.util.ArrayList;
68  import java.util.Iterator;
69  import java.util.List;
70  import java.util.Map;
71  
72  /**
73   * Base class for artifact tasks.
74   *
75   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
76   * @version $Id: AbstractArtifactTask.java 773075 2009-05-08 20:16:17Z pgier $
77   */
78  public abstract class AbstractArtifactTask
79      extends Task
80  {
81      private static ClassLoader plexusClassLoader;
82  
83      private File userSettingsFile;
84  
85      private File globalSettingsFile;
86  
87      private Settings settings;
88  
89      private ProfileManager profileManager;
90  
91      private PlexusContainer container;
92  
93      private Pom pom;
94  
95      private String pomRefId;
96  
97      private LocalRepository localRepository;
98  
99      protected ArtifactRepository createLocalArtifactRepository()
100     {
101         if ( localRepository == null )
102         {
103             localRepository = getDefaultLocalRepository();
104         }
105 
106         ArtifactRepositoryLayout repositoryLayout =
107             (ArtifactRepositoryLayout) lookup( ArtifactRepositoryLayout.ROLE, localRepository.getLayout() );
108 
109         return new DefaultArtifactRepository( "local", "file://" + localRepository.getPath(), repositoryLayout );
110     }
111 
112     /**
113      * Create a core-Maven ArtifactRepositoryFactory from a Maven Ant Tasks's RemoteRepository definition,
114      * eventually configured with authentication and proxy information.
115      * @param repository the remote repository as defined in Ant
116      * @return the corresponding ArtifactRepositoryFactory
117      */
118     protected ArtifactRepositoryFactory getArtifactRepositoryFactory( RemoteRepository repository )
119     {
120         WagonManager manager = (WagonManager) lookup( WagonManager.ROLE );
121 
122         Authentication authentication = repository.getAuthentication();
123         if ( authentication != null )
124         {
125             manager.addAuthenticationInfo( repository.getId(), authentication.getUserName(),
126                                            authentication.getPassword(), authentication.getPrivateKey(),
127                                            authentication.getPassphrase() );
128         }
129 
130         Proxy proxy = repository.getProxy();
131         if ( proxy != null )
132         {
133             manager.addProxy( proxy.getType(), proxy.getHost(), proxy.getPort(), proxy.getUserName(),
134                               proxy.getPassword(), proxy.getNonProxyHosts() );
135         }
136 
137         return (ArtifactRepositoryFactory) lookup( ArtifactRepositoryFactory.ROLE );
138     }
139 
140     protected void releaseArtifactRepositoryFactory( ArtifactRepositoryFactory repositoryFactory )
141     {
142         try
143         {
144             getContainer().release( repositoryFactory );
145         }
146         catch ( ComponentLifecycleException e )
147         {
148             // TODO: Warn the user, or not?
149         }
150     }
151 
152     /**
153      * Create a core-Maven ArtifactRepository from a Maven Ant Tasks's RemoteRepository definition.
154      * @param repository the remote repository as defined in Ant
155      * @return the corresponding ArtifactRepository
156      */
157     protected ArtifactRepository createRemoteArtifactRepository( RemoteRepository repository )
158     {
159         ArtifactRepositoryLayout repositoryLayout =
160             (ArtifactRepositoryLayout) lookup( ArtifactRepositoryLayout.ROLE, repository.getLayout() );
161 
162         ArtifactRepositoryFactory repositoryFactory = null;
163 
164         ArtifactRepository artifactRepository;
165 
166         try
167         {
168             repositoryFactory = getArtifactRepositoryFactory( repository );
169 
170             ArtifactRepositoryPolicy snapshots = buildArtifactRepositoryPolicy( repository.getSnapshots() );
171             ArtifactRepositoryPolicy releases = buildArtifactRepositoryPolicy( repository.getReleases() );
172 
173             artifactRepository = repositoryFactory.createArtifactRepository( repository.getId(), repository.getUrl(),
174                                                                              repositoryLayout, snapshots, releases );
175         }
176         finally
177         {
178             releaseArtifactRepositoryFactory( repositoryFactory );
179         }
180 
181         return artifactRepository;
182     }
183 
184     private static ArtifactRepositoryPolicy buildArtifactRepositoryPolicy( RepositoryPolicy policy )
185     {
186         boolean enabled = true;
187         String updatePolicy = null;
188         String checksumPolicy = null;
189 
190         if ( policy != null )
191         {
192             enabled = policy.isEnabled();
193             if ( policy.getUpdatePolicy() != null )
194             {
195                 updatePolicy = policy.getUpdatePolicy();
196             }
197             if ( policy.getChecksumPolicy() != null )
198             {
199                 checksumPolicy = policy.getChecksumPolicy();
200             }
201         }
202 
203         return new ArtifactRepositoryPolicy( enabled, updatePolicy, checksumPolicy );
204     }
205 
206     protected LocalRepository getDefaultLocalRepository()
207     {
208         Settings settings = getSettings();
209         LocalRepository localRepository = new LocalRepository();
210         localRepository.setId( "local" );
211         localRepository.setPath( new File( settings.getLocalRepository() ) );
212         return localRepository;
213     }
214 
215     protected synchronized Settings getSettings()
216     {
217         if ( settings == null )
218         {
219             initSettings();
220         }
221         return settings;
222     }
223 
224     private File newFile( String parent, String subdir, String filename )
225     {
226         return new File( new File( parent, subdir ), filename );
227     }
228 
229     private void initSettings()
230     {
231         if ( userSettingsFile == null )
232         {
233             File tempSettingsFile = newFile( System.getProperty( "user.home" ), ".ant", "settings.xml" );
234             if ( tempSettingsFile.exists() )
235             {
236                 userSettingsFile = tempSettingsFile;
237             }
238             else
239             {
240                 tempSettingsFile = newFile( System.getProperty( "user.home" ), ".m2", "settings.xml" );
241                 if ( tempSettingsFile.exists() )
242                 {
243                     userSettingsFile = tempSettingsFile;
244                 }
245             }
246         }
247         if ( globalSettingsFile == null )
248         {
249             File tempSettingsFile = newFile( System.getProperty( "ant.home" ), "etc", "settings.xml" );
250             if ( tempSettingsFile.exists() )
251             {
252                 globalSettingsFile = tempSettingsFile;
253             }
254             else
255             {
256                 // look in ${M2_HOME}/conf
257                 List env = Execute.getProcEnvironment();
258                 for ( Iterator iter = env.iterator(); iter.hasNext(); )
259                 {
260                     String var = (String) iter.next();
261                     if ( var.startsWith( "M2_HOME=" ) )
262                     {
263                         String m2Home = var.substring( "M2_HOME=".length() );
264                         tempSettingsFile = newFile( m2Home, "conf", "settings.xml" );
265                         if ( tempSettingsFile.exists() )
266                         {
267                             globalSettingsFile = tempSettingsFile;
268                         }
269                         break;
270                     }
271                 }
272             }
273         }
274 
275         Settings userSettings = loadSettings( userSettingsFile );
276         Settings globalSettings = loadSettings( globalSettingsFile );
277 
278         SettingsUtils.merge( userSettings, globalSettings, TrackableBase.GLOBAL_LEVEL );
279         settings = userSettings;
280 
281         if ( StringUtils.isEmpty( settings.getLocalRepository() ) )
282         {
283             String location = newFile( System.getProperty( "user.home" ), ".m2", "repository" ).getAbsolutePath();
284             settings.setLocalRepository( location );
285         }
286 
287         WagonManager wagonManager = (WagonManager) lookup( WagonManager.ROLE );
288         wagonManager.setDownloadMonitor( new AntDownloadMonitor() );
289         if ( settings.isOffline() )
290         {
291             log( "You are working in offline mode.", Project.MSG_INFO );
292             wagonManager.setOnline( false );
293         }
294         else
295         {
296             wagonManager.setOnline( true );
297         }
298     }
299 
300     private Settings loadSettings( File settingsFile )
301     {
302         Settings settings = null;
303         try
304         {
305             if ( settingsFile != null )
306             {
307                 log( "Loading Maven settings file: " + settingsFile.getPath(), Project.MSG_VERBOSE );
308                 settings = readSettings( settingsFile );
309             }
310         }
311         catch ( IOException e )
312         {
313             log( "Error reading settings file '" + settingsFile + "' - ignoring. Error was: " + e.getMessage(),
314                  Project.MSG_WARN );
315         }
316         catch ( XmlPullParserException e )
317         {
318             log( "Error parsing settings file '" + settingsFile + "' - ignoring. Error was: " + e.getMessage(),
319                  Project.MSG_WARN );
320         }
321 
322         if ( settings == null )
323         {
324             settings = new Settings();
325             RuntimeInfo rtInfo = new RuntimeInfo( settings );
326             settings.setRuntimeInfo( rtInfo );
327         }
328 
329         return settings;
330     }
331 
332     public void setSettingsFile( File settingsFile )
333     {
334         if ( !settingsFile.exists() )
335         {
336             throw new BuildException( "settingsFile does not exist: " + settingsFile.getAbsolutePath() );
337         }
338 
339         userSettingsFile = settingsFile;
340         settings = null;
341     }
342 
343     /**
344      * @see org.apache.maven.settings.DefaultMavenSettingsBuilder#readSettings
345      */
346     private Settings readSettings( File settingsFile )
347         throws IOException, XmlPullParserException
348     {
349         Settings settings = null;
350         Reader reader = null;
351         try
352         {
353             reader = ReaderFactory.newXmlReader( settingsFile );
354             StringWriter sWriter = new StringWriter();
355 
356             IOUtil.copy( reader, sWriter );
357 
358             String rawInput = sWriter.toString();
359 
360             try
361             {
362                 RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
363                 interpolator.addValueSource( new EnvarBasedValueSource() );
364 
365                 rawInput = interpolator.interpolate( rawInput, "settings" );
366             }
367             catch ( Exception e )
368             {
369                 log( "Failed to initialize environment variable resolver. Skipping environment substitution in "
370                      + "settings." );
371             }
372 
373             StringReader sReader = new StringReader( rawInput );
374 
375             SettingsXpp3Reader modelReader = new SettingsXpp3Reader();
376 
377             settings = modelReader.read( sReader );
378 
379             RuntimeInfo rtInfo = new RuntimeInfo( settings );
380 
381             rtInfo.setFile( settingsFile );
382 
383             settings.setRuntimeInfo( rtInfo );
384         }
385         finally
386         {
387             IOUtil.close( reader );
388         }
389         return settings;
390     }
391 
392     protected RemoteRepository createAntRemoteRepository( org.apache.maven.model.Repository pomRepository )
393     {
394         RemoteRepository r = createAntRemoteRepositoryBase( pomRepository );
395 
396         if ( pomRepository.getSnapshots() != null )
397         {
398             r.addSnapshots( convertRepositoryPolicy( pomRepository.getSnapshots() ) );
399         }
400         if ( pomRepository.getReleases() != null )
401         {
402             r.addReleases( convertRepositoryPolicy( pomRepository.getReleases() ) );
403         }
404 
405         return r;
406     }
407 
408     protected RemoteRepository createAntRemoteRepositoryBase( org.apache.maven.model.RepositoryBase pomRepository )
409     {
410         RemoteRepository r = new RemoteRepository();
411         r.setId( pomRepository.getId() );
412         r.setUrl( pomRepository.getUrl() );
413         r.setLayout( pomRepository.getLayout() );
414 
415         updateRepositoryWithSettings( r );
416         return r;
417     }
418 
419     protected void updateRepositoryWithSettings( RemoteRepository repository )
420     {
421         // TODO: actually, we need to not funnel this through the ant repository - we should pump settings into wagon
422         // manager at the start like m2 does, and then match up by repository id
423         // As is, this could potentially cause a problem with 2 remote repositories with different authentication info
424 
425         if ( repository.getAuthentication() == null )
426         {
427             Server server = getSettings().getServer( repository.getId() );
428             if ( server != null )
429             {
430                 repository.addAuthentication( new Authentication( server ) );
431             }
432         }
433          
434         if ( repository.getProxy() == null )
435         {
436             org.apache.maven.settings.Proxy proxy = getSettings().getActiveProxy();
437             if ( proxy != null )
438             {
439                 repository.addProxy( new Proxy( proxy ) );
440             }
441         }
442          
443         Mirror mirror = getSettings().getMirrorOf( repository.getId() );
444         if ( mirror == null )
445         {
446             mirror = getSettings().getMirrorOf( "*" );
447         }
448         if ( mirror != null )
449         {
450             repository.setUrl( mirror.getUrl() );
451         }
452     }
453          
454     protected Object lookup( String role )
455     {
456         try
457         {
458             return getContainer().lookup( role );
459         }
460         catch ( ComponentLookupException e )
461         {
462             throw new BuildException( "Unable to find component: " + role, e );
463         }
464     }
465 
466     protected Object lookup( String role,
467                              String roleHint )
468     {
469         try
470         {
471             return getContainer().lookup( role, roleHint );
472         }
473         catch ( ComponentLookupException e )
474         {
475             throw new BuildException( "Unable to find component: " + role + "[" + roleHint + "]", e );
476         }
477     }
478 
479     protected synchronized PlexusContainer getContainer()
480     {
481         if ( container == null )
482         {
483             container = (PlexusContainer) getProject().getReference( PlexusContainer.class.getName() );
484 
485             if ( container == null )
486             {
487                 try
488                 {
489                     ClassWorld classWorld = new ClassWorld();
490 
491                     classWorld.newRealm( "plexus.core", getClass().getClassLoader() );
492 
493                     Embedder embedder = new Embedder();
494 
495                     embedder.start( classWorld );
496 
497                     container = embedder.getContainer();
498                 }
499                 catch ( PlexusContainerException e )
500                 {
501                     throw new BuildException( "Unable to start embedder", e );
502                 }
503                 catch ( DuplicateRealmException e )
504                 {
505                     throw new BuildException( "Unable to create embedder ClassRealm", e );
506                 }
507 
508                 getProject().addReference( PlexusContainer.class.getName(), container );
509             }
510         }
511 
512         return container;
513     }
514 
515     public Pom buildPom( ArtifactRepository localArtifactRepository )
516     {
517         if ( pomRefId != null && pom != null )
518         {
519             throw new BuildException( "You cannot specify both a POM element and a pomrefid element" );
520         }
521 
522         Pom pom = this.pom;
523         if ( pomRefId != null )
524         {
525             pom = (Pom) getProject().getReference( pomRefId );
526             if ( pom == null )
527             {
528                 throw new BuildException( "Reference '" + pomRefId + "' was not found." );
529             }
530         }
531 
532         if ( pom != null )
533         {
534             MavenProjectBuilder projectBuilder = (MavenProjectBuilder) lookup( MavenProjectBuilder.ROLE );
535             pom.initialise( projectBuilder, localArtifactRepository );
536         }
537         return pom;
538     }
539 
540     protected Pom createDummyPom( ArtifactRepository localArtifactRepository )
541     {
542         MavenProjectBuilder projectBuilder = (MavenProjectBuilder) lookup( MavenProjectBuilder.ROLE );
543 
544         MavenProject mavenProject;
545         try
546         {
547             mavenProject = projectBuilder.buildStandaloneSuperProject( localArtifactRepository, getProfileManager() );
548         }
549         catch ( ProjectBuildingException e )
550         {
551             throw new BuildException( "Unable to create dummy Pom", e );
552         }
553 
554         Pom pom = new Pom();
555 
556         pom.setMavenProject( mavenProject );
557 
558         return pom;
559     }
560     
561     protected Artifact createDummyArtifact()
562     {
563         ArtifactFactory factory = (ArtifactFactory) lookup( ArtifactFactory.ROLE );
564         // TODO: maybe not strictly correct, while we should enforce that packaging has a type handler of the same id, we don't
565         return factory.createBuildArtifact( "unspecified", "unspecified", "0.0", "jar" );
566     }
567 
568     public String[] getSupportedProtocols()
569     {
570         try
571         {
572             Map wagonMap = getContainer().lookupMap( Wagon.ROLE );
573             List protocols = new ArrayList();
574             for ( Iterator iter = wagonMap.entrySet().iterator(); iter.hasNext(); )
575             {
576                 Map.Entry entry = (Map.Entry) iter.next();
577                 protocols.add( entry.getKey() );
578             }
579             return (String[]) protocols.toArray( new String[protocols.size()] );
580         }
581         catch ( ComponentLookupException e )
582         {
583             throw new BuildException( "Unable to lookup Wagon providers", e );
584         }
585     }
586 
587     public String getSupportedProtocolsAsString()
588     {
589         return StringUtils.join( getSupportedProtocols(), ", " );
590     }
591     
592     public void diagnoseError( Throwable error )
593     {
594         try
595         {
596             ErrorDiagnostics diagnostics = (ErrorDiagnostics) container.lookup( ErrorDiagnostics.ROLE );
597 
598             StringBuffer message = new StringBuffer();
599 
600             message.append( "An error has occurred while processing the Maven artifact tasks.\n" );
601             message.append( " Diagnosis:\n\n" );
602 
603             message.append( diagnostics.diagnose( error ) );
604 
605             message.append( "\n\n" );
606 
607             log( message.toString(), Project.MSG_INFO );
608         }
609         catch ( ComponentLookupException e )
610         {
611             log( "Failed to retrieve error diagnoser.", Project.MSG_DEBUG );
612         }
613     }
614 
615     public void addPom( Pom pom )
616     {
617         this.pom = pom;
618     }
619 
620     public String getPomRefId()
621     {
622         return pomRefId;
623     }
624 
625     public void setPomRefId( String pomRefId )
626     {
627         this.pomRefId = pomRefId;
628     }
629 
630     public LocalRepository getLocalRepository()
631     {
632         return localRepository;
633     }
634 
635     protected ProfileManager getProfileManager()
636     {
637         if ( profileManager == null )
638         {
639             profileManager = new DefaultProfileManager( getContainer(), getSettings(), System.getProperties() );
640         }
641         return profileManager;
642     }
643 
644     public void addLocalRepository( LocalRepository localRepository )
645     {
646         this.localRepository = localRepository;
647     }
648 
649     public void setProfiles( String profiles )
650     {
651         if ( profiles != null )
652         {
653             // TODO: not sure this is the best way to do this...
654             log( "Profiles not yet supported, ignoring profiles '" + profiles + "'", Project.MSG_WARN );
655 //            System.setProperty( ProfileActivationUtils.ACTIVE_PROFILE_IDS, profiles );
656         }
657     }
658 
659     private static RepositoryPolicy convertRepositoryPolicy( org.apache.maven.model.RepositoryPolicy pomRepoPolicy )
660     {
661         RepositoryPolicy policy = new RepositoryPolicy();
662         policy.setEnabled( pomRepoPolicy.isEnabled() );
663         policy.setUpdatePolicy( pomRepoPolicy.getUpdatePolicy() );
664         return policy;
665     }
666 
667     /** @noinspection RefusedBequest */
668     public void execute()
669     {
670         ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
671         try
672         {
673             if ( plexusClassLoader != null )
674             {
675                 Thread.currentThread().setContextClassLoader( plexusClassLoader );
676             }
677             initSettings();
678             doExecute();
679         }
680         catch ( BuildException e )
681         {
682             diagnoseError( e );
683 
684             throw e;
685         }
686         finally
687         {
688             plexusClassLoader = Thread.currentThread().getContextClassLoader();
689             Thread.currentThread().setContextClassLoader( originalClassLoader );
690         }
691     }
692 
693     protected abstract void doExecute();
694 }