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