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 1531347 2013-10-11 16:38:02Z rfscholte $
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 to be deployed 
61       */
62      private static final AtomicInteger readyProjectsCounter = new AtomicInteger();
63      
64      private static final List<DeployRequest> deployRequests =
65                      Collections.synchronizedList( new ArrayList<DeployRequest>() );
66  
67      /**
68       */
69      @Component
70      private MavenProject project;
71  
72      @Parameter( defaultValue = "${reactorProjects}", required = true, readonly = true )
73      private List<MavenProject> reactorProjects;
74  
75      /**
76       * Whether every project should be deployed during its own deploy-phase or at the end of the multimodule build. If
77       * set to {@code true} and the build fails, none of the reactor projects is deployed
78       * 
79       * @since 2.8
80       */
81      @Parameter( defaultValue = "false", property = "deployAtEnd" )
82      private boolean deployAtEnd;
83  
84      /**
85       * @deprecated either use project.getArtifact() or reactorProjects.get(i).getArtifact()
86       */
87      @Parameter( defaultValue = "${project.artifact}", required = true, readonly = true )
88      private Artifact artifact;
89  
90      /**
91       * @deprecated either use project.getPackaging() or reactorProjects.get(i).getPackaging()
92       */
93      @Parameter( defaultValue = "${project.packaging}", required = true, readonly = true )
94      private String packaging;
95  
96      /**
97       * @deprecated either use project.getFile() or reactorProjects.get(i).getFile()
98       */
99      @Parameter( defaultValue = "${project.file}", required = true, readonly = true )
100     private File pomFile;
101 
102     /**
103      * Specifies an alternative repository to which the project artifacts should be deployed ( other than those
104      * specified in &lt;distributionManagement&gt; ). <br/>
105      * Format: id::layout::url
106      * <dl>
107      * <dt>id</dt>
108      * <dd>The id can be used to pick up the correct credentials from the settings.xml</dd>
109      * <dt>layout</dt>
110      * <dd>Either <code>default</code> for the Maven2 layout or <code>legacy</code> for the Maven1 layout. Maven3 also
111      * uses the <code>default</code> layout.</dd>
112      * <dt>url</dt>
113      * <dd>The location of the repository</dd>
114      * </dl>
115      */
116     @Parameter( property = "altDeploymentRepository" )
117     private String altDeploymentRepository;
118 
119     /**
120      * The alternative repository to use when the project has a snapshot version.
121      * 
122      * @since 2.8
123      * @see DeployMojo#altDeploymentRepository
124      */
125     @Parameter( property = "altSnapshotDeploymentRepository" )
126     private String altSnapshotDeploymentRepository;
127 
128     /**
129      * The alternative repository to use when the project has a final version.
130      * 
131      * @since 2.8
132      * @see DeployMojo#altDeploymentRepository
133      */
134     @Parameter( property = "altReleaseDeploymentRepository" )
135     private String altReleaseDeploymentRepository;
136 
137     /**
138      * @deprecated either use project.getAttachedArtifacts() or reactorProjects.get(i).getAttachedArtifacts()
139      */
140     @Parameter( defaultValue = "${project.attachedArtifacts}", required = true, readonly = true )
141     private List attachedArtifacts;
142 
143     /**
144      * Set this to 'true' to bypass artifact deploy
145      * 
146      * @since 2.4
147      */
148     @Parameter( property = "maven.deploy.skip", defaultValue = "false" )
149     private boolean skip;
150 
151     public void execute()
152         throws MojoExecutionException, MojoFailureException
153     {
154         boolean projectsReady = readyProjectsCounter.incrementAndGet() == reactorProjects.size();
155         
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                 if ( !projectsReady )
175                 {
176                     getLog().info( "Deploying " + project.getGroupId() + ":" + project.getArtifactId() + ":"
177                                        + project.getVersion() + " at end" );
178                 }
179             }
180         }
181 
182         if ( projectsReady )
183         {
184             synchronized ( deployRequests )
185             {
186                 while( !deployRequests.isEmpty() )
187                 {
188                     deployProject( deployRequests.remove( 0 ) );
189                 }
190             }
191         }
192     }
193 
194     private void deployProject( DeployRequest request )
195         throws MojoExecutionException, MojoFailureException
196     {
197         Artifact artifact = request.getProject().getArtifact();
198         String packaging = request.getProject().getPackaging();
199         File pomFile = request.getProject().getFile();
200 
201         @SuppressWarnings( "unchecked" )
202         List<Artifact> attachedArtifacts = request.getProject().getAttachedArtifacts();
203 
204         ArtifactRepository repo =
205             getDeploymentRepository( request.getProject(), request.getAltDeploymentRepository(),
206                                      request.getAltReleaseDeploymentRepository(),
207                                      request.getAltSnapshotDeploymentRepository() );
208 
209         String protocol = repo.getProtocol();
210 
211         if ( protocol.equalsIgnoreCase( "scp" ) )
212         {
213             File sshFile = new File( System.getProperty( "user.home" ), ".ssh" );
214 
215             if ( !sshFile.exists() )
216             {
217                 sshFile.mkdirs();
218             }
219         }
220 
221         // Deploy the POM
222         boolean isPomArtifact = "pom".equals( packaging );
223         if ( !isPomArtifact )
224         {
225             ArtifactMetadata metadata = new ProjectArtifactMetadata( artifact, pomFile );
226             artifact.addMetadata( metadata );
227         }
228 
229         if ( request.isUpdateReleaseInfo() )
230         {
231             artifact.setRelease( true );
232         }
233         
234         int retryFailedDeploymentCount = request.getRetryFailedDeploymentCount();
235 
236         try
237         {
238             if ( isPomArtifact )
239             {
240                 deploy( pomFile, artifact, repo, getLocalRepository(), retryFailedDeploymentCount );
241             }
242             else
243             {
244                 File file = artifact.getFile();
245 
246                 if ( file != null && file.isFile() )
247                 {
248                     deploy( file, artifact, repo, getLocalRepository(), retryFailedDeploymentCount );
249                 }
250                 else if ( !attachedArtifacts.isEmpty() )
251                 {
252                     getLog().info( "No primary artifact to deploy, deploying attached artifacts instead." );
253 
254                     Artifact pomArtifact =
255                         artifactFactory.createProjectArtifact( artifact.getGroupId(), artifact.getArtifactId(),
256                                                                artifact.getBaseVersion() );
257                     pomArtifact.setFile( pomFile );
258                     if ( request.isUpdateReleaseInfo() )
259                     {
260                         pomArtifact.setRelease( true );
261                     }
262 
263                     deploy( pomFile, pomArtifact, repo, getLocalRepository(), retryFailedDeploymentCount );
264 
265                     // propagate the timestamped version to the main artifact for the attached artifacts to pick it up
266                     artifact.setResolvedVersion( pomArtifact.getVersion() );
267                 }
268                 else
269                 {
270                     String message = "The packaging for this project did not assign a file to the build artifact";
271                     throw new MojoExecutionException( message );
272                 }
273             }
274 
275             for ( Artifact attached : attachedArtifacts )
276             {
277                 deploy( attached.getFile(), attached, repo, getLocalRepository(), retryFailedDeploymentCount );
278             }
279         }
280         catch ( ArtifactDeploymentException e )
281         {
282             throw new MojoExecutionException( e.getMessage(), e );
283         }
284     }
285 
286     ArtifactRepository getDeploymentRepository( MavenProject project, String altDeploymentRepository, String altReleaseDeploymentRepository, String altSnapshotDeploymentRepository )
287         throws MojoExecutionException, MojoFailureException
288     {
289         ArtifactRepository repo = null;
290 
291         String altDeploymentRepo;
292         if ( ArtifactUtils.isSnapshot( project.getVersion() ) && altSnapshotDeploymentRepository != null )
293         {
294             altDeploymentRepo = altSnapshotDeploymentRepository;
295         }
296         else if ( !ArtifactUtils.isSnapshot( project.getVersion() ) && altReleaseDeploymentRepository != null )
297         {
298             altDeploymentRepo = altReleaseDeploymentRepository;
299         }
300         else
301         {
302             altDeploymentRepo = altDeploymentRepository;
303         }
304 
305         if ( altDeploymentRepo != null )
306         {
307             getLog().info( "Using alternate deployment repository " + altDeploymentRepo );
308 
309             Matcher matcher = ALT_REPO_SYNTAX_PATTERN.matcher( altDeploymentRepo );
310 
311             if ( !matcher.matches() )
312             {
313                 throw new MojoFailureException( altDeploymentRepo, "Invalid syntax for repository.",
314                                                 "Invalid syntax for alternative repository. Use \"id::layout::url\"." );
315             }
316             else
317             {
318                 String id = matcher.group( 1 ).trim();
319                 String layout = matcher.group( 2 ).trim();
320                 String url = matcher.group( 3 ).trim();
321 
322                 ArtifactRepositoryLayout repoLayout = getLayout( layout );
323 
324                 repo = repositoryFactory.createDeploymentArtifactRepository( id, url, repoLayout, true );
325             }
326         }
327 
328         if ( repo == null )
329         {
330             repo = project.getDistributionManagementArtifactRepository();
331         }
332 
333         if ( repo == null )
334         {
335             String msg =
336                 "Deployment failed: repository element was not specified in the POM inside"
337                     + " distributionManagement element or in -DaltDeploymentRepository=id::layout::url parameter";
338 
339             throw new MojoExecutionException( msg );
340         }
341 
342         return repo;
343     }
344 
345 }