View Javadoc
1   package org.apache.maven.plugin.deploy;
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.ArtifactUtils;
24  import org.apache.maven.artifact.deployer.ArtifactDeploymentException;
25  import org.apache.maven.artifact.metadata.ArtifactMetadata;
26  import org.apache.maven.artifact.repository.ArtifactRepository;
27  import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
28  import org.apache.maven.plugin.MojoExecutionException;
29  import org.apache.maven.plugin.MojoFailureException;
30  import org.apache.maven.plugins.annotations.Component;
31  import org.apache.maven.plugins.annotations.LifecyclePhase;
32  import org.apache.maven.plugins.annotations.Mojo;
33  import org.apache.maven.plugins.annotations.Parameter;
34  import org.apache.maven.project.MavenProject;
35  import org.apache.maven.project.artifact.ProjectArtifactMetadata;
36  
37  import java.io.File;
38  import java.util.ArrayList;
39  import java.util.Collections;
40  import java.util.List;
41  import java.util.concurrent.atomic.AtomicInteger;
42  import java.util.regex.Matcher;
43  import java.util.regex.Pattern;
44  
45  /**
46   * Deploys an artifact to remote repository.
47   * 
48   * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
49   * @author <a href="mailto:jdcasey@apache.org">John Casey (refactoring only)</a>
50   * @version $Id: DeployMojo.java 1620080 2014-08-23 21:34:57Z khmarbaise $
51   */
52  @Mojo( name = "deploy", defaultPhase = LifecyclePhase.DEPLOY, threadSafe = true )
53  public class DeployMojo
54      extends AbstractDeployMojo
55  {
56  
57      private static final Pattern ALT_REPO_SYNTAX_PATTERN = Pattern.compile( "(.+)::(.+)::(.+)" );
58  
59      /**
60       * When building with multiple threads, reaching the last project doesn't have to mean that all projects are ready
61       * to be deployed
62       */
63      private static final AtomicInteger readyProjectsCounter = new AtomicInteger();
64  
65      private static final List<DeployRequest> deployRequests =
66          Collections.synchronizedList( new ArrayList<DeployRequest>() );
67  
68      /**
69       */
70      @Parameter( defaultValue = "${project}", readonly = true, required = true )
71      private MavenProject project;
72  
73      @Parameter( defaultValue = "${reactorProjects}", required = true, readonly = true )
74      private List<MavenProject> reactorProjects;
75  
76      /**
77       * Whether every project should be deployed during its own deploy-phase or at the end of the multimodule build. If
78       * set to {@code true} and the build fails, none of the reactor projects is deployed. <strong>(experimental)</strong>
79       * 
80       * @since 2.8
81       */
82      @Parameter( defaultValue = "false", property = "deployAtEnd" )
83      private boolean deployAtEnd;
84  
85      /**
86       * @deprecated either use project.getArtifact() or reactorProjects.get(i).getArtifact()
87       */
88      @Parameter( defaultValue = "${project.artifact}", required = true, readonly = true )
89      private Artifact artifact;
90  
91      /**
92       * @deprecated either use project.getPackaging() or reactorProjects.get(i).getPackaging()
93       */
94      @Parameter( defaultValue = "${project.packaging}", required = true, readonly = true )
95      private String packaging;
96  
97      /**
98       * @deprecated either use project.getFile() or reactorProjects.get(i).getFile()
99       */
100     @Parameter( defaultValue = "${project.file}", required = true, readonly = true )
101     private File pomFile;
102 
103     /**
104      * Specifies an alternative repository to which the project artifacts should be deployed ( other than those
105      * specified in &lt;distributionManagement&gt; ). <br/>
106      * Format: id::layout::url
107      * <dl>
108      * <dt>id</dt>
109      * <dd>The id can be used to pick up the correct credentials from the settings.xml</dd>
110      * <dt>layout</dt>
111      * <dd>Either <code>default</code> for the Maven2 layout or <code>legacy</code> for the Maven1 layout. Maven3 also
112      * uses the <code>default</code> layout.</dd>
113      * <dt>url</dt>
114      * <dd>The location of the repository</dd>
115      * </dl>
116      */
117     @Parameter( property = "altDeploymentRepository" )
118     private String altDeploymentRepository;
119 
120     /**
121      * The alternative repository to use when the project has a snapshot version.
122      * 
123      * @since 2.8
124      * @see DeployMojo#altDeploymentRepository
125      */
126     @Parameter( property = "altSnapshotDeploymentRepository" )
127     private String altSnapshotDeploymentRepository;
128 
129     /**
130      * The alternative repository to use when the project has a final version.
131      * 
132      * @since 2.8
133      * @see DeployMojo#altDeploymentRepository
134      */
135     @Parameter( property = "altReleaseDeploymentRepository" )
136     private String altReleaseDeploymentRepository;
137 
138     /**
139      * @deprecated either use project.getAttachedArtifacts() or reactorProjects.get(i).getAttachedArtifacts()
140      */
141     @Parameter( defaultValue = "${project.attachedArtifacts}", required = true, readonly = true )
142     private List attachedArtifacts;
143 
144     /**
145      * Set this to 'true' to bypass artifact deploy
146      * 
147      * @since 2.4
148      */
149     @Parameter( property = "maven.deploy.skip", defaultValue = "false" )
150     private boolean skip;
151 
152     public void execute()
153         throws MojoExecutionException, MojoFailureException
154     {
155         boolean addedDeployRequest = false;
156         if ( skip )
157         {
158             getLog().info( "Skipping artifact deployment" );
159         }
160         else
161         {
162             failIfOffline();
163 
164             DeployRequest currentExecutionDeployRequest =
165                 new DeployRequest().setProject( project ).setUpdateReleaseInfo( isUpdateReleaseInfo() ).setRetryFailedDeploymentCount( getRetryFailedDeploymentCount() ).setAltReleaseDeploymentRepository( altReleaseDeploymentRepository ).setAltSnapshotDeploymentRepository( altSnapshotDeploymentRepository ).setAltDeploymentRepository( altDeploymentRepository );
166 
167             if ( !deployAtEnd )
168             {
169                 deployProject( currentExecutionDeployRequest );
170             }
171             else
172             {
173                 deployRequests.add( currentExecutionDeployRequest );
174                 addedDeployRequest = true;
175             }
176         }
177 
178         boolean projectsReady = readyProjectsCounter.incrementAndGet() == reactorProjects.size();
179         if ( projectsReady )
180         {
181             synchronized ( deployRequests )
182             {
183                 while ( !deployRequests.isEmpty() )
184                 {
185                     deployProject( deployRequests.remove( 0 ) );
186                 }
187             }
188         }
189         else if ( addedDeployRequest )
190         {
191             getLog().info( "Deploying " + project.getGroupId() + ":" + project.getArtifactId() + ":"
192                                + project.getVersion() + " at end" );
193         }
194     }
195 
196     private void deployProject( DeployRequest request )
197         throws MojoExecutionException, MojoFailureException
198     {
199         Artifact artifact = request.getProject().getArtifact();
200         String packaging = request.getProject().getPackaging();
201         File pomFile = request.getProject().getFile();
202 
203         @SuppressWarnings( "unchecked" )
204         List<Artifact> attachedArtifacts = request.getProject().getAttachedArtifacts();
205 
206         ArtifactRepository repo =
207             getDeploymentRepository( request.getProject(), request.getAltDeploymentRepository(),
208                                      request.getAltReleaseDeploymentRepository(),
209                                      request.getAltSnapshotDeploymentRepository() );
210 
211         String protocol = repo.getProtocol();
212 
213         if ( protocol.equalsIgnoreCase( "scp" ) )
214         {
215             File sshFile = new File( System.getProperty( "user.home" ), ".ssh" );
216 
217             if ( !sshFile.exists() )
218             {
219                 sshFile.mkdirs();
220             }
221         }
222 
223         // Deploy the POM
224         boolean isPomArtifact = "pom".equals( packaging );
225         if ( !isPomArtifact )
226         {
227             ArtifactMetadata metadata = new ProjectArtifactMetadata( artifact, pomFile );
228             artifact.addMetadata( metadata );
229         }
230 
231         if ( request.isUpdateReleaseInfo() )
232         {
233             artifact.setRelease( true );
234         }
235 
236         int retryFailedDeploymentCount = request.getRetryFailedDeploymentCount();
237 
238         try
239         {
240             if ( isPomArtifact )
241             {
242                 deploy( pomFile, artifact, repo, getLocalRepository(), retryFailedDeploymentCount );
243             }
244             else
245             {
246                 File file = artifact.getFile();
247 
248                 if ( file != null && file.isFile() )
249                 {
250                     deploy( file, artifact, repo, getLocalRepository(), retryFailedDeploymentCount );
251                 }
252                 else if ( !attachedArtifacts.isEmpty() )
253                 {
254                     getLog().info( "No primary artifact to deploy, deploying attached artifacts instead." );
255 
256                     Artifact pomArtifact =
257                         artifactFactory.createProjectArtifact( artifact.getGroupId(), artifact.getArtifactId(),
258                                                                artifact.getBaseVersion() );
259                     pomArtifact.setFile( pomFile );
260                     if ( request.isUpdateReleaseInfo() )
261                     {
262                         pomArtifact.setRelease( true );
263                     }
264 
265                     deploy( pomFile, pomArtifact, repo, getLocalRepository(), retryFailedDeploymentCount );
266 
267                     // propagate the timestamped version to the main artifact for the attached artifacts to pick it up
268                     artifact.setResolvedVersion( pomArtifact.getVersion() );
269                 }
270                 else
271                 {
272                     String message = "The packaging for this project did not assign a file to the build artifact";
273                     throw new MojoExecutionException( message );
274                 }
275             }
276 
277             for ( Artifact attached : attachedArtifacts )
278             {
279                 deploy( attached.getFile(), attached, repo, getLocalRepository(), retryFailedDeploymentCount );
280             }
281         }
282         catch ( ArtifactDeploymentException e )
283         {
284             throw new MojoExecutionException( e.getMessage(), e );
285         }
286     }
287 
288     ArtifactRepository getDeploymentRepository( MavenProject project, String altDeploymentRepository,
289                                                 String altReleaseDeploymentRepository,
290                                                 String altSnapshotDeploymentRepository )
291         throws MojoExecutionException, MojoFailureException
292     {
293         ArtifactRepository repo = null;
294 
295         String altDeploymentRepo;
296         if ( ArtifactUtils.isSnapshot( project.getVersion() ) && altSnapshotDeploymentRepository != null )
297         {
298             altDeploymentRepo = altSnapshotDeploymentRepository;
299         }
300         else if ( !ArtifactUtils.isSnapshot( project.getVersion() ) && altReleaseDeploymentRepository != null )
301         {
302             altDeploymentRepo = altReleaseDeploymentRepository;
303         }
304         else
305         {
306             altDeploymentRepo = altDeploymentRepository;
307         }
308 
309         if ( altDeploymentRepo != null )
310         {
311             getLog().info( "Using alternate deployment repository " + altDeploymentRepo );
312 
313             Matcher matcher = ALT_REPO_SYNTAX_PATTERN.matcher( altDeploymentRepo );
314 
315             if ( !matcher.matches() )
316             {
317                 throw new MojoFailureException( altDeploymentRepo, "Invalid syntax for repository.",
318                                                 "Invalid syntax for alternative repository. Use \"id::layout::url\"." );
319             }
320             else
321             {
322                 String id = matcher.group( 1 ).trim();
323                 String layout = matcher.group( 2 ).trim();
324                 String url = matcher.group( 3 ).trim();
325 
326                 ArtifactRepositoryLayout repoLayout = getLayout( layout );
327 
328                 repo = repositoryFactory.createDeploymentArtifactRepository( id, url, repoLayout, true );
329             }
330         }
331 
332         if ( repo == null )
333         {
334             repo = project.getDistributionManagementArtifactRepository();
335         }
336 
337         if ( repo == null )
338         {
339             String msg =
340                 "Deployment failed: repository element was not specified in the POM inside"
341                     + " distributionManagement element or in -DaltDeploymentRepository=id::layout::url parameter";
342 
343             throw new MojoExecutionException( msg );
344         }
345 
346         return repo;
347     }
348 
349 }