View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugins.dependency.fromDependencies;
20  
21  import java.io.File;
22  import java.util.Collections;
23  import java.util.Map;
24  import java.util.Set;
25  
26  import org.apache.maven.artifact.Artifact;
27  import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
28  import org.apache.maven.plugin.MojoExecutionException;
29  import org.apache.maven.plugins.annotations.Component;
30  import org.apache.maven.plugins.annotations.LifecyclePhase;
31  import org.apache.maven.plugins.annotations.Mojo;
32  import org.apache.maven.plugins.annotations.Parameter;
33  import org.apache.maven.plugins.annotations.ResolutionScope;
34  import org.apache.maven.plugins.dependency.utils.DependencyStatusSets;
35  import org.apache.maven.plugins.dependency.utils.DependencyUtil;
36  import org.apache.maven.plugins.dependency.utils.filters.DestFileFilter;
37  import org.apache.maven.project.ProjectBuildingRequest;
38  import org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter;
39  import org.apache.maven.shared.transfer.artifact.DefaultArtifactCoordinate;
40  import org.apache.maven.shared.transfer.artifact.install.ArtifactInstaller;
41  import org.apache.maven.shared.transfer.artifact.install.ArtifactInstallerException;
42  import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResolverException;
43  
44  /**
45   * Goal that copies the project dependencies from the repository to a defined location.
46   *
47   * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
48   * @since 1.0
49   */
50  // CHECKSTYLE_OFF: LineLength
51  @Mojo(
52          name = "copy-dependencies",
53          requiresDependencyResolution = ResolutionScope.TEST,
54          defaultPhase = LifecyclePhase.PROCESS_SOURCES,
55          threadSafe = true)
56  // CHECKSTYLE_ON: LineLength
57  public class CopyDependenciesMojo extends AbstractFromDependenciesMojo {
58      /**
59       * Also copy the pom of each artifact.
60       *
61       * @since 2.0
62       */
63      @Parameter(property = "mdep.copyPom", defaultValue = "false")
64      protected boolean copyPom = true;
65  
66      /**
67       *
68       */
69      @Component
70      private ArtifactInstaller installer;
71  
72      /**
73       *
74       */
75      @Component(role = ArtifactRepositoryLayout.class)
76      private Map<String, ArtifactRepositoryLayout> repositoryLayouts;
77  
78      /**
79       * Either append the artifact's baseVersion or uniqueVersion to the filename. Will only be used if
80       * {@link #isStripVersion()} is {@code false}.
81       *
82       * @since 2.6
83       */
84      @Parameter(property = "mdep.useBaseVersion", defaultValue = "true")
85      protected boolean useBaseVersion = true;
86  
87      /**
88       * Add parent poms to the list of copied dependencies (both current project pom parents and dependencies parents).
89       *
90       * @since 2.8
91       */
92      @Parameter(property = "mdep.addParentPoms", defaultValue = "false")
93      protected boolean addParentPoms;
94  
95      /**
96       * <i>not used in this goal</i>
97       */
98      @Parameter
99      protected boolean ignorePermissions;
100 
101     /**
102      * Main entry into mojo. Gets the list of dependencies and iterates through calling copyArtifact.
103      *
104      * @throws MojoExecutionException with a message if an error occurs.
105      * @see #getDependencySets(boolean, boolean)
106      * @see #copyArtifact(Artifact, boolean, boolean, boolean, boolean)
107      */
108     @Override
109     protected void doExecute() throws MojoExecutionException {
110         DependencyStatusSets dss = getDependencySets(this.failOnMissingClassifierArtifact, addParentPoms);
111         Set<Artifact> artifacts = dss.getResolvedDependencies();
112 
113         if (!useRepositoryLayout) {
114             for (Artifact artifact : artifacts) {
115                 copyArtifact(
116                         artifact, isStripVersion(), this.prependGroupId, this.useBaseVersion, this.stripClassifier);
117             }
118         } else {
119             ProjectBuildingRequest buildingRequest = getRepositoryManager()
120                     .setLocalRepositoryBasedir(session.getProjectBuildingRequest(), outputDirectory);
121 
122             artifacts.forEach(artifact -> installArtifact(artifact, buildingRequest));
123         }
124 
125         Set<Artifact> skippedArtifacts = dss.getSkippedDependencies();
126         for (Artifact artifact : skippedArtifacts) {
127             getLog().info(artifact.getId() + " already exists in destination.");
128         }
129 
130         if (isCopyPom() && !useRepositoryLayout) {
131             copyPoms(getOutputDirectory(), artifacts, this.stripVersion);
132             copyPoms(getOutputDirectory(), skippedArtifacts, this.stripVersion, this.stripClassifier); // Artifacts
133             // that already
134             // exist may
135             // not yet have
136             // poms
137         }
138     }
139 
140     /**
141      * install the artifact and the corresponding pom if copyPoms=true
142      *
143      * @param artifact
144      * @param buildingRequest
145      */
146     private void installArtifact(Artifact artifact, ProjectBuildingRequest buildingRequest) {
147         try {
148             installer.install(buildingRequest, Collections.singletonList(artifact));
149             installBaseSnapshot(artifact, buildingRequest);
150 
151             if (!"pom".equals(artifact.getType()) && isCopyPom()) {
152                 Artifact pomArtifact = getResolvedPomArtifact(artifact);
153                 if (pomArtifact != null
154                         && pomArtifact.getFile() != null
155                         && pomArtifact.getFile().exists()) {
156                     installer.install(buildingRequest, Collections.singletonList(pomArtifact));
157                     installBaseSnapshot(pomArtifact, buildingRequest);
158                 }
159             }
160         } catch (ArtifactInstallerException e) {
161             getLog().warn("unable to install " + artifact, e);
162         }
163     }
164 
165     private void installBaseSnapshot(Artifact artifact, ProjectBuildingRequest buildingRequest)
166             throws ArtifactInstallerException {
167         if (artifact.isSnapshot() && !artifact.getBaseVersion().equals(artifact.getVersion())) {
168             String version = artifact.getVersion();
169             try {
170                 artifact.setVersion(artifact.getBaseVersion());
171                 installer.install(buildingRequest, Collections.singletonList(artifact));
172             } finally {
173                 artifact.setVersion(version);
174             }
175         }
176     }
177 
178     /**
179      * Copies the Artifact after building the destination file name if overridden. This method also checks if the
180      * classifier is set and adds it to the destination file name if needed.
181      *
182      * @param artifact representing the object to be copied.
183      * @param removeVersion specifies if the version should be removed from the file name when copying.
184      * @param prependGroupId specifies if the groupId should be prepend to the file while copying.
185      * @param theUseBaseVersion specifies if the baseVersion of the artifact should be used instead of the version.
186      * @throws MojoExecutionException with a message if an error occurs.
187      * @see #copyArtifact(Artifact, boolean, boolean, boolean, boolean)
188      */
189     protected void copyArtifact(
190             Artifact artifact, boolean removeVersion, boolean prependGroupId, boolean theUseBaseVersion)
191             throws MojoExecutionException {
192         copyArtifact(artifact, removeVersion, prependGroupId, theUseBaseVersion, false);
193     }
194 
195     /**
196      * Copies the Artifact after building the destination file name if overridden. This method also checks if the
197      * classifier is set and adds it to the destination file name if needed.
198      *
199      * @param artifact representing the object to be copied.
200      * @param removeVersion specifies if the version should be removed from the file name when copying.
201      * @param prependGroupId specifies if the groupId should be prepend to the file while copying.
202      * @param theUseBaseVersion specifies if the baseVersion of the artifact should be used instead of the version.
203      * @param removeClassifier specifies if the classifier should be removed from the file name when copying.
204      * @throws MojoExecutionException with a message if an error occurs.
205      * @see #copyFile(File, File)
206      * @see DependencyUtil#getFormattedOutputDirectory(boolean, boolean, boolean, boolean, boolean, boolean, File, Artifact)
207      */
208     protected void copyArtifact(
209             Artifact artifact,
210             boolean removeVersion,
211             boolean prependGroupId,
212             boolean theUseBaseVersion,
213             boolean removeClassifier)
214             throws MojoExecutionException {
215 
216         String destFileName = DependencyUtil.getFormattedFileName(
217                 artifact, removeVersion, prependGroupId, theUseBaseVersion, removeClassifier);
218 
219         File destDir = DependencyUtil.getFormattedOutputDirectory(
220                 useSubDirectoryPerScope,
221                 useSubDirectoryPerType,
222                 useSubDirectoryPerArtifact,
223                 useRepositoryLayout,
224                 stripVersion,
225                 stripType,
226                 outputDirectory,
227                 artifact);
228         File destFile = new File(destDir, destFileName);
229 
230         copyFile(artifact.getFile(), destFile);
231     }
232 
233     /**
234      * Copy the pom files associated with the artifacts.
235      *
236      * @param destDir The destination directory {@link File}.
237      * @param artifacts The artifacts {@link Artifact}.
238      * @param removeVersion remove version or not.
239      * @throws MojoExecutionException in case of errors.
240      */
241     public void copyPoms(File destDir, Set<Artifact> artifacts, boolean removeVersion) throws MojoExecutionException {
242 
243         copyPoms(destDir, artifacts, removeVersion, false);
244     }
245 
246     /**
247      * Copy the pom files associated with the artifacts.
248      *
249      * @param destDir The destination directory {@link File}.
250      * @param artifacts The artifacts {@link Artifact}.
251      * @param removeVersion remove version or not.
252      * @param removeClassifier remove the classifier or not.
253      * @throws MojoExecutionException in case of errors.
254      */
255     public void copyPoms(File destDir, Set<Artifact> artifacts, boolean removeVersion, boolean removeClassifier)
256             throws MojoExecutionException {
257 
258         for (Artifact artifact : artifacts) {
259             Artifact pomArtifact = getResolvedPomArtifact(artifact);
260 
261             // Copy the pom
262             if (pomArtifact != null
263                     && pomArtifact.getFile() != null
264                     && pomArtifact.getFile().exists()) {
265                 File pomDestFile = new File(
266                         destDir,
267                         DependencyUtil.getFormattedFileName(
268                                 pomArtifact, removeVersion, prependGroupId, useBaseVersion, removeClassifier));
269                 if (!pomDestFile.exists()) {
270                     copyFile(pomArtifact.getFile(), pomDestFile);
271                 }
272             }
273         }
274     }
275 
276     /**
277      * @param artifact {@link Artifact}
278      * @return {@link Artifact}
279      */
280     protected Artifact getResolvedPomArtifact(Artifact artifact) {
281         DefaultArtifactCoordinate coordinate = new DefaultArtifactCoordinate();
282         coordinate.setGroupId(artifact.getGroupId());
283         coordinate.setArtifactId(artifact.getArtifactId());
284         coordinate.setVersion(artifact.getVersion());
285         coordinate.setExtension("pom");
286 
287         Artifact pomArtifact = null;
288         // Resolve the pom artifact using repos
289         try {
290             ProjectBuildingRequest buildingRequest = newResolveArtifactProjectBuildingRequest();
291 
292             pomArtifact = getArtifactResolver()
293                     .resolveArtifact(buildingRequest, coordinate)
294                     .getArtifact();
295         } catch (ArtifactResolverException e) {
296             getLog().info(e.getMessage());
297         }
298         return pomArtifact;
299     }
300 
301     @Override
302     protected ArtifactsFilter getMarkedArtifactFilter() {
303         return new DestFileFilter(
304                 this.overWriteReleases,
305                 this.overWriteSnapshots,
306                 this.overWriteIfNewer,
307                 this.useSubDirectoryPerArtifact,
308                 this.useSubDirectoryPerType,
309                 this.useSubDirectoryPerScope,
310                 this.useRepositoryLayout,
311                 this.stripVersion,
312                 this.prependGroupId,
313                 this.useBaseVersion,
314                 this.outputDirectory);
315     }
316 
317     /**
318      * @return true, if the pom of each artifact must be copied
319      */
320     public boolean isCopyPom() {
321         return this.copyPom;
322     }
323 
324     /**
325      * @param copyPom - true if the pom of each artifact must be copied
326      */
327     public void setCopyPom(boolean copyPom) {
328         this.copyPom = copyPom;
329     }
330 }