View Javadoc
1   package org.apache.maven.shared.test.plugin;
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 java.io.File;
23  import java.io.IOException;
24  import java.io.Reader;
25  import java.net.MalformedURLException;
26  
27  import org.apache.maven.artifact.Artifact;
28  import org.apache.maven.artifact.factory.ArtifactFactory;
29  import org.apache.maven.artifact.installer.ArtifactInstallationException;
30  import org.apache.maven.artifact.installer.ArtifactInstaller;
31  import org.apache.maven.artifact.repository.ArtifactRepository;
32  import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
33  import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
34  import org.apache.maven.execution.DefaultMavenExecutionRequest;
35  import org.apache.maven.execution.DefaultMavenExecutionResult;
36  import org.apache.maven.execution.MavenSession;
37  import org.apache.maven.model.Model;
38  import org.apache.maven.model.Parent;
39  import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
40  import org.apache.maven.plugin.LegacySupport;
41  import org.apache.maven.project.MavenProject;
42  import org.apache.maven.project.artifact.ProjectArtifactMetadata;
43  import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
44  import org.apache.maven.settings.MavenSettingsBuilder;
45  import org.apache.maven.settings.Settings;
46  import org.codehaus.plexus.PlexusConstants;
47  import org.codehaus.plexus.PlexusContainer;
48  import org.codehaus.plexus.component.annotations.Component;
49  import org.codehaus.plexus.component.annotations.Requirement;
50  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
51  import org.codehaus.plexus.context.Context;
52  import org.codehaus.plexus.context.ContextException;
53  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
54  import org.codehaus.plexus.util.IOUtil;
55  import org.codehaus.plexus.util.ReaderFactory;
56  import org.codehaus.plexus.util.StringUtils;
57  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
58  
59  /**
60   * Tools to access and manage Maven repositories for test builds, including construction of a local
61   * repository directory structure.
62   *
63   * <p>
64   * <b>WARNING:</b> Currently, the <code>createLocalRepositoryFromPlugin</code> method will not
65   * resolve parent POMs that exist <b>only</b> in your normal local repository, and are not reachable
66   * using the relativePath element. This may result in failed test builds, as one or more of the
67   * plugin's ancestor POMs cannot be resolved.
68   * </p>
69   *
70   * @author jdcasey
71   * @version $Id$
72   */
73  @Deprecated
74  @Component( role = RepositoryTool.class )
75  public class RepositoryTool
76      implements Contextualizable
77  {
78      /** Plexus role */
79      public static final String ROLE = RepositoryTool.class.getName();
80  
81      @Requirement
82      private ArtifactRepositoryFactory repositoryFactory;
83  
84      @Requirement
85      private MavenSettingsBuilder settingsBuilder;
86  
87      @Requirement
88      private ArtifactFactory artifactFactory;
89  
90      @Requirement
91      private ArtifactInstaller artifactInstaller;
92  
93      @Requirement
94      private LegacySupport legacySupport;
95  
96      // contextualized.
97      private PlexusContainer container;
98  
99      /**
100      * Lookup and return the location of the normal Maven local repository.
101      *
102      * @return the location of the normal Maven local repository.
103      * @throws TestToolsException if any
104      */
105     public File findLocalRepositoryDirectory()
106         throws TestToolsException
107     {
108         String localRepo = System.getProperty( "maven.local.repo" );
109         if ( StringUtils.isNotEmpty( localRepo ) )
110         {
111             return new File( localRepo );
112         }
113 
114         Settings settings;
115         try
116         {
117             DefaultMavenExecutionRequest request = new DefaultMavenExecutionRequest();
118             request.setUserSettingsFile( new File( System.getProperty( "user.home" ), ".m2/settings.xml" ) );
119             request.setGlobalSettingsFile( new File( System.getProperty( "maven.home" ), "conf/settings.xml" ) );
120             settings = settingsBuilder.buildSettings( request );
121         }
122         catch ( IOException e )
123         {
124             throw new TestToolsException( "Error building Maven settings.", e );
125         }
126         catch ( XmlPullParserException e )
127         {
128             throw new TestToolsException( "Error building Maven settings.", e );
129         }
130 
131         if ( settings == null || settings.getLocalRepository() == null
132             || settings.getLocalRepository().trim().length() < 1 )
133         {
134             return new File( System.getProperty( "user.home" ), ".m2/repository" );
135         }
136 
137         return new File( settings.getLocalRepository() );
138     }
139 
140     /**
141      * Construct an ArtifactRepository instance that refers to the normal Maven local repository.
142      *
143      * @return an ArtifactRepository instance
144      * @throws TestToolsException if any
145      */
146     public ArtifactRepository createLocalArtifactRepositoryInstance()
147         throws TestToolsException
148     {
149         File localRepoDir = findLocalRepositoryDirectory();
150 
151         return createLocalArtifactRepositoryInstance( localRepoDir );
152     }
153 
154     /**
155      * Construct an ArtifactRepository instance that refers to the test-time Maven local repository.
156      *
157      * @param localRepositoryDirectory The location of the local repository to be used for test builds.
158      * @return an ArtifactRepository instance
159      * @throws TestToolsException if any
160      */
161     public ArtifactRepository createLocalArtifactRepositoryInstance( File localRepositoryDirectory )
162         throws TestToolsException
163     {
164         ArtifactRepositoryLayout defaultLayout;
165         try
166         {
167             defaultLayout = (ArtifactRepositoryLayout) container.lookup( ArtifactRepositoryLayout.ROLE, "default" );
168         }
169         catch ( ComponentLookupException e )
170         {
171             throw new TestToolsException( "Error retrieving default repository layout.", e );
172         }
173 
174         try
175         {
176             return repositoryFactory.createArtifactRepository( "local", localRepositoryDirectory.toURL()
177                 .toExternalForm(), defaultLayout, null, null );
178         }
179         catch ( MalformedURLException e )
180         {
181             throw new TestToolsException( "Error converting local repo directory to a URL.", e );
182         }
183     }
184 
185     /**
186      * Install a test version of a plugin - along with its POM, and as many ancestor POMs as can be
187      * reached using the &lt;relativePath/&gt; element - to a clean local repository directory for
188      * use in test builds.
189      *
190      * <p>
191      * <b>WARNING:</b> Currently, this method will not resolve parent POMs that exist <b>only</b> in
192      * your normal local repository, and are not reachable using the relativePath element. This may
193      * result in failed test builds, as one or more of the plugin's ancestor POMs cannot be resolved.
194      * </p>
195      *
196      * @param project
197      * @param realPomFile
198      * @param targetLocalRepoBasedir
199      * @throws TestToolsException if any
200      */
201     public void createLocalRepositoryFromComponentProject( MavenProject project, File realPomFile,
202                                                            File targetLocalRepoBasedir )
203         throws TestToolsException
204     {
205         Artifact artifact = project.getArtifact();
206 
207         if ( "pom".equals( project.getPackaging() ) )
208         {
209             artifact.setFile( project.getFile() );
210         }
211 
212         ArtifactRepository localRepository = createLocalArtifactRepositoryInstance( targetLocalRepoBasedir );
213 
214         String localPath = localRepository.pathOf( artifact );
215 
216         File destination = new File( localRepository.getBasedir(), localPath );
217         if ( !destination.getParentFile().exists() )
218         {
219             destination.getParentFile().mkdirs();
220         }
221 
222         legacySupport.setSession( new MavenSession( container, MavenRepositorySystemUtils.newSession(),
223                                                     new DefaultMavenExecutionRequest(),
224                                                     new DefaultMavenExecutionResult() ) );
225         try
226         {
227             artifactInstaller.install( artifact.getFile(), artifact, localRepository );
228         }
229         catch ( ArtifactInstallationException e )
230         {
231             throw new TestToolsException( "Error installing plugin artifact to target local repository: "
232                 + targetLocalRepoBasedir, e );
233         }
234         finally
235         {
236             legacySupport.setSession( null );
237         }
238 
239         installLocallyReachableAncestorPoms( realPomFile, localRepository );
240     }
241 
242     /**
243      * Traverse &lt;relativePath/&gt; links for successive POMs in the plugin's ancestry, installing
244      * each one into the test-time local repository.
245      *
246      * @param realPomFile The real plugin POM; a starting point, but the POM is already installed,
247      *   so we won't actually install this file, only use it to locate parents.
248      * @param localRepo The test-time local repository instance
249      * @throws TestToolsException if any
250      */
251     private void installLocallyReachableAncestorPoms( File realPomFile, ArtifactRepository localRepo )
252         throws TestToolsException
253     {
254         MavenXpp3Reader pomReader = new MavenXpp3Reader();
255 
256         File pom = realPomFile;
257 
258         boolean firstPass = true;
259 
260         while ( pom != null )
261         {
262 
263             if ( !pom.exists() )
264             {
265                 pom = null;
266                 break;
267             }
268 
269             String pomGroupId = null;
270             String pomArtifactId = null;
271             String pomVersion = null;
272 
273             Reader reader = null;
274 
275             File currentPom = pom;
276 
277             try
278             {
279                 reader = ReaderFactory.newXmlReader( pom );
280 
281                 Model model = pomReader.read( reader );
282 
283                 pomGroupId = model.getGroupId();
284                 pomArtifactId = model.getArtifactId();
285                 pomVersion = model.getVersion();
286 
287                 Parent parent = model.getParent();
288                 if ( parent != null )
289                 {
290                     pom = new File( pom.getParentFile(), parent.getRelativePath() );
291 
292                     if ( pomGroupId == null )
293                     {
294                         pomGroupId = parent.getGroupId();
295                     }
296 
297                     if ( pomVersion == null )
298                     {
299                         pomVersion = parent.getVersion();
300                     }
301                 }
302                 else
303                 {
304                     pom = null;
305                 }
306             }
307             catch ( IOException e )
308             {
309                 throw new TestToolsException( "Error reading ancestor POM: " + currentPom, e );
310             }
311             catch ( XmlPullParserException e )
312             {
313                 throw new TestToolsException( "Error reading ancestor POM: " + currentPom, e );
314             }
315             finally
316             {
317                 IOUtil.close( reader );
318             }
319 
320             if ( !firstPass )
321             {
322                 Artifact pomArtifact = artifactFactory.createProjectArtifact( pomGroupId, pomArtifactId, pomVersion );
323                 pomArtifact.addMetadata( new ProjectArtifactMetadata( pomArtifact, currentPom ) );
324 
325                 try
326                 {
327                     artifactInstaller.install( currentPom, pomArtifact, localRepo );
328                 }
329                 catch ( ArtifactInstallationException e )
330                 {
331                     throw new TestToolsException( "Error installing ancestor POM: " + currentPom
332                         + " to target local repository: " + localRepo.getBasedir(), e );
333                 }
334             }
335             else
336             {
337                 firstPass = false;
338             }
339         }
340     }
341 
342     /**
343      * Retrieve the PlexusContainer instance used to instantiate this component. The container is
344      * used to retrieve the default ArtifactRepositoryLayout component, for use in constructing
345      * instances of ArtifactRepository that can be used to access local repositories.
346      *
347      * @see org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable#contextualize(org.codehaus.plexus.context.Context)
348      */
349     public void contextualize( Context context )
350         throws ContextException
351     {
352         this.container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
353     }
354 }