View Javadoc
1   package org.apache.maven.plugins.assembly.repository;
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 javax.inject.Inject;
23  import javax.inject.Named;
24  import javax.inject.Singleton;
25  
26  import java.io.File;
27  import java.io.IOException;
28  import java.util.ArrayList;
29  import java.util.Collection;
30  import java.util.HashMap;
31  import java.util.List;
32  import java.util.Map;
33  import java.util.Set;
34  
35  import org.apache.commons.io.FileUtils;
36  import org.apache.maven.artifact.Artifact;
37  import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
38  import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
39  import org.apache.maven.model.Dependency;
40  import org.apache.maven.plugins.assembly.repository.model.GroupVersionAlignment;
41  import org.apache.maven.plugins.assembly.repository.model.RepositoryInfo;
42  import org.apache.maven.project.MavenProject;
43  import org.apache.maven.project.ProjectBuildingRequest;
44  import org.apache.maven.shared.artifact.filter.PatternExcludesArtifactFilter;
45  import org.apache.maven.shared.artifact.filter.PatternIncludesArtifactFilter;
46  import org.apache.maven.shared.artifact.filter.ScopeArtifactFilter;
47  import org.apache.maven.shared.transfer.artifact.TransferUtils;
48  import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResolver;
49  import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResolverException;
50  import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResult;
51  import org.apache.maven.shared.transfer.dependencies.resolve.DependencyResolver;
52  import org.apache.maven.shared.transfer.dependencies.resolve.DependencyResolverException;
53  import org.apache.maven.shared.transfer.repository.RepositoryManager;
54  import org.slf4j.Logger;
55  import org.slf4j.LoggerFactory;
56  
57  import static java.util.Objects.requireNonNull;
58  
59  /**
60   * @author Jason van Zyl
61   */
62  
63  // todo will need to pop the processed project cache using reflection
64  @Singleton
65  @Named
66  public class DefaultRepositoryAssembler implements RepositoryAssembler
67  {
68      private static final Logger LOGGER = LoggerFactory.getLogger( DefaultRepositoryAssembler.class );
69  
70      private final ArtifactResolver artifactResolver;
71  
72      private final RepositoryManager repositoryManager;
73  
74      private final DependencyResolver dependencyResolver;
75  
76      @Inject
77      public DefaultRepositoryAssembler( ArtifactResolver artifactResolver,
78                                         RepositoryManager repositoryManager,
79                                         DependencyResolver dependencyResolver )
80      {
81          this.artifactResolver = requireNonNull( artifactResolver );
82          this.repositoryManager = requireNonNull( repositoryManager );
83          this.dependencyResolver = requireNonNull( dependencyResolver );
84      }
85  
86      public void buildRemoteRepository( File repositoryDirectory, RepositoryInfo repository,
87                                         RepositoryBuilderConfigSource configSource )
88                                             throws RepositoryAssemblyException
89      {
90          MavenProject project = configSource.getProject();
91          ProjectBuildingRequest buildingRequest = configSource.getProjectBuildingRequest();
92  
93          Iterable<ArtifactResult> result;
94  
95          Collection<Dependency> dependencies = project.getDependencies();
96  
97          if ( dependencies == null )
98          {
99              if ( LOGGER.isDebugEnabled() )
100             {
101                 LOGGER.debug( "dependency-artifact set for project: " + project.getId()
102                     + " is null. Skipping repository processing." );
103             }
104 
105             return;
106         }
107 
108         Collection<Dependency> managedDependencies = null;
109         if ( project.getDependencyManagement() != null )
110         {
111             managedDependencies = project.getDependencyManagement().getDependencies();
112         }
113 
114         // Older Aether versions use an cache which can't be cleared. So can't delete repoDir and use it again.
115         // Instead create a temporary repository, delete it at end (should be in a finally-block)
116 
117         File tempRepo = new File( repositoryDirectory.getParentFile(), repositoryDirectory.getName() + "_tmp" );
118 
119         buildingRequest = repositoryManager.setLocalRepositoryBasedir( buildingRequest, tempRepo );
120 
121         try
122         {
123             result = dependencyResolver.resolveDependencies( buildingRequest, dependencies, managedDependencies, null );
124         }
125         catch ( DependencyResolverException e )
126         {
127             throw new RepositoryAssemblyException( "Error resolving artifacts: " + e.getMessage(), e );
128         }
129 
130         ArtifactFilter filter = buildRepositoryFilter( repository, project );
131 
132         buildingRequest = repositoryManager.setLocalRepositoryBasedir( buildingRequest, repositoryDirectory );
133 
134         Map<String, GroupVersionAlignment> groupVersionAlignments =
135             createGroupVersionAlignments( repository.getGroupVersionAlignments() );
136 
137         assembleRepositoryArtifacts( buildingRequest, result, filter, groupVersionAlignments );
138 
139         if ( repository.isIncludeMetadata() )
140         {
141 //            assembleRepositoryMetadata( result, filter, centralRepository, targetRepository );
142         }
143 
144         try
145         {
146             FileUtils.deleteDirectory( tempRepo );
147         }
148         catch ( IOException e )
149         {
150             // noop
151         }
152     }
153 
154     private ArtifactFilter buildRepositoryFilter( RepositoryInfo repository, MavenProject project )
155     {
156         AndArtifactFilter filter = new AndArtifactFilter();
157 
158         ArtifactFilter scopeFilter = new ScopeArtifactFilter( repository.getScope() );
159         filter.add( scopeFilter );
160 
161         // ----------------------------------------------------------------------------
162         // Includes
163         //
164         // We'll take everything if no includes are specified to try and make
165         // this
166         // process more maintainable. Don't want to have to update the assembly
167         // descriptor everytime the POM is updated.
168         // ----------------------------------------------------------------------------
169 
170         List<String> includes = repository.getIncludes();
171 
172         if ( ( includes == null ) || includes.isEmpty() )
173         {
174             List<String> patterns = new ArrayList<>();
175 
176             Set<Artifact> projectArtifacts = project.getDependencyArtifacts();
177 
178             if ( projectArtifacts != null )
179             {
180                 for ( Artifact artifact : projectArtifacts )
181                 {
182                     patterns.add( artifact.getDependencyConflictId() );
183                 }
184             }
185 
186             PatternIncludesArtifactFilter includeFilter = new PatternIncludesArtifactFilter( patterns, true );
187 
188             filter.add( includeFilter );
189         }
190         else
191         {
192             filter.add( new PatternIncludesArtifactFilter( repository.getIncludes(), true ) );
193         }
194 
195         // ----------------------------------------------------------------------------
196         // Excludes
197         //
198         // We still want to make it easy to exclude a few things even if we
199         // slurp
200         // up everything.
201         // ----------------------------------------------------------------------------
202 
203         List<String> excludes = repository.getExcludes();
204 
205         if ( ( excludes != null ) && !excludes.isEmpty() )
206         {
207             filter.add( new PatternExcludesArtifactFilter( repository.getExcludes(), true ) );
208         }
209 
210         return filter;
211     }
212 
213     private void assembleRepositoryArtifacts( ProjectBuildingRequest buildingRequest, Iterable<ArtifactResult> result,
214                                               ArtifactFilter filter,
215                                               Map<String, GroupVersionAlignment> groupVersionAlignments )
216                                                   throws RepositoryAssemblyException
217     {
218         try
219         {
220             for ( ArtifactResult ar : result )
221             {
222                 Artifact a = ar.getArtifact();
223 
224                 if ( filter.include( a ) )
225                 {
226                     LOGGER.debug( "Re-resolving: " + a + " for repository assembly." );
227 
228                     setAlignment( a, groupVersionAlignments );
229 
230                     artifactResolver.resolveArtifact( buildingRequest, TransferUtils.toArtifactCoordinate( a ) );
231 
232                     a.setVersion( a.getBaseVersion() );
233 
234                     File targetFile = new File( repositoryManager.getLocalRepositoryBasedir( buildingRequest ),
235                                                 repositoryManager.getPathForLocalArtifact( buildingRequest, a ) );
236                     
237                     FileUtils.copyFile( a.getFile(), targetFile );
238 
239 //                    writeChecksums( targetFile );
240                 }
241             }
242         }
243         catch ( ArtifactResolverException e )
244         {
245             throw new RepositoryAssemblyException( "Error resolving artifacts: " + e.getMessage(), e );
246         }
247         catch ( IOException e )
248         {
249             throw new RepositoryAssemblyException( "Error writing artifact metdata.", e );
250         }
251     }
252 
253     // CHECKSTYLE_OFF: LineLength
254     protected Map<String, GroupVersionAlignment> createGroupVersionAlignments( List<GroupVersionAlignment> versionAlignments )
255     // CHECKSTYLE_ON: LineLength
256     {
257         Map<String, GroupVersionAlignment> groupVersionAlignments = new HashMap<>();
258 
259         if ( versionAlignments != null )
260         {
261             for ( GroupVersionAlignment alignment : versionAlignments )
262             {
263                 groupVersionAlignments.put( alignment.getId(), alignment );
264             }
265         }
266 
267         return groupVersionAlignments;
268     }
269 
270     private void setAlignment( Artifact artifact, Map<String, GroupVersionAlignment> groupVersionAlignments )
271     {
272         GroupVersionAlignment alignment = groupVersionAlignments.get( artifact.getGroupId() );
273 
274         if ( alignment != null )
275         {
276             if ( !alignment.getExcludes().contains( artifact.getArtifactId() ) )
277             {
278                 artifact.setVersion( alignment.getVersion() );
279             }
280         }
281     }
282 }