View Javadoc
1   package org.apache.maven.shared.transfer.project.deploy.internal;
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 java.io.File;
23  import java.io.IOException;
24  import java.util.ArrayList;
25  import java.util.Collection;
26  import java.util.List;
27  
28  import org.apache.maven.artifact.Artifact;
29  import org.apache.maven.artifact.metadata.ArtifactMetadata;
30  import org.apache.maven.artifact.repository.ArtifactRepository;
31  import org.apache.maven.project.ProjectBuildingRequest;
32  import org.apache.maven.project.artifact.ProjectArtifactMetadata;
33  import org.apache.maven.shared.transfer.artifact.deploy.ArtifactDeployer;
34  import org.apache.maven.shared.transfer.artifact.deploy.ArtifactDeployerException;
35  import org.apache.maven.shared.transfer.project.MavenAetherUtils;
36  import org.apache.maven.shared.transfer.project.NoFileAssignedException;
37  import org.apache.maven.shared.transfer.project.deploy.ProjectDeployer;
38  import org.apache.maven.shared.transfer.project.deploy.ProjectDeployerRequest;
39  import org.apache.maven.shared.transfer.repository.RepositoryManager;
40  import org.codehaus.plexus.component.annotations.Component;
41  import org.codehaus.plexus.component.annotations.Requirement;
42  import org.codehaus.plexus.util.FileUtils;
43  import org.slf4j.Logger;
44  import org.slf4j.LoggerFactory;
45  
46  /**
47   * This will deploy a whole project into the appropriate remote repository.
48   * 
49   * @author Karl Heinz Marbaise <a href="mailto:khmarbaise@apache.org">khmarbaise@apache.org</a> Most of the code is
50   *         taken from maven-deploy-plugin.
51   */
52  @Component( role = ProjectDeployer.class )
53  class DefaultProjectDeployer
54      implements ProjectDeployer
55  {
56      private static final Logger LOGGER = LoggerFactory.getLogger( DefaultProjectDeployer.class );
57  
58      @Requirement
59      private ArtifactDeployer deployer;
60  
61      @Requirement
62      private RepositoryManager repositoryManager;
63  
64      private final DualDigester digester = new DualDigester();
65  
66      /**
67       * {@inheritDoc}
68       */
69      public void deploy( ProjectBuildingRequest buildingRequest, ProjectDeployerRequest projectDeployerRequest,
70                          ArtifactRepository artifactRepository )
71          throws NoFileAssignedException, IllegalArgumentException, ArtifactDeployerException
72      {
73          validateParameters( buildingRequest, projectDeployerRequest, artifactRepository );
74  
75          MavenAetherUtils.importAetherLibrary();
76  
77          Artifact artifact = projectDeployerRequest.getProject().getArtifact();
78          String packaging = projectDeployerRequest.getProject().getPackaging();
79          File pomFile = projectDeployerRequest.getProject().getFile();
80  
81          List<Artifact> attachedArtifacts = projectDeployerRequest.getProject().getAttachedArtifacts();
82  
83          // Deploy the POM
84          boolean isPomArtifact = "pom".equals( packaging );
85          if ( isPomArtifact )
86          {
87              artifact.setFile( pomFile );
88          }
89          else
90          {
91              ProjectArtifactMetadata metadata = new ProjectArtifactMetadata( artifact, pomFile );
92              artifact.addMetadata( metadata );
93          }
94  
95          // What consequence does this have?
96          // artifact.setRelease( true );
97  
98          artifact.setRepository( artifactRepository );
99  
100         int retryFailedDeploymentCount = projectDeployerRequest.getRetryFailedDeploymentCount();
101 
102         List<Artifact> deployableArtifacts = new ArrayList<Artifact>();
103         if ( isPomArtifact )
104         {
105             deployableArtifacts.add( artifact );
106         }
107         else
108         {
109             File file = artifact.getFile();
110 
111             if ( file != null && file.isFile() )
112             {
113                 deployableArtifacts.add( artifact );
114             }
115             else if ( !attachedArtifacts.isEmpty() )
116             {
117                 // TODO: Reconsider this exception? Better Exception type?
118                 throw new NoFileAssignedException( "The packaging plugin for this project did not assign "
119                     + "a main file to the project but it has attachments. Change packaging to 'pom'." );
120             }
121             else
122             {
123                 // TODO: Reconsider this exception? Better Exception type?
124                 throw new NoFileAssignedException( "The packaging for this project did not assign "
125                     + "a file to the build artifact" );
126             }
127         }
128 
129         for ( Artifact attached : attachedArtifacts )
130         {
131             deployableArtifacts.add( attached );
132         }
133 
134         installChecksumsForAllArtifacts( buildingRequest, deployableArtifacts );
135         deploy( buildingRequest, deployableArtifacts, artifactRepository, retryFailedDeploymentCount );
136     }
137 
138     private void validateParameters( ProjectBuildingRequest buildingRequest,
139                                      ProjectDeployerRequest projectDeployerRequest,
140                                      ArtifactRepository artifactRepository )
141     {
142         if ( buildingRequest == null )
143         {
144             throw new IllegalArgumentException( "The parameter buildingRequest is not allowed to be null." );
145         }
146         if ( projectDeployerRequest == null )
147         {
148             throw new IllegalArgumentException( "The parameter projectDeployerRequest is not allowed to be null." );
149         }
150         if ( artifactRepository == null )
151         {
152             throw new IllegalArgumentException( "The parameter artifactRepository is not allowed to be null." );
153         }
154     }
155 
156     private void installChecksumsForAllArtifacts( ProjectBuildingRequest request, Collection<Artifact> artifacts )
157     {
158         for ( Artifact item : artifacts )
159         {
160             try
161             {
162                 LOGGER.debug( "Installing checksum for " + item.getId() );
163                 installChecksums( request, item );
164             }
165             catch ( IOException e )
166             {
167                 // THINK HARD ABOUT IT
168                 LOGGER.error( "Failure during checksum generation for " + item.getId() );
169             }
170         }
171     }
172 
173     private void deploy( ProjectBuildingRequest request, Collection<Artifact> artifacts,
174                          ArtifactRepository deploymentRepository, int retryFailedDeploymentCount )
175         throws ArtifactDeployerException
176     {
177 
178         // for now retry means redeploy the complete artifacts collection
179         int retryFailedDeploymentCounter = Math.max( 1, Math.min( 10, retryFailedDeploymentCount ) );
180         ArtifactDeployerException exception = null;
181         for ( int count = 0; count < retryFailedDeploymentCounter; count++ )
182         {
183             try
184             {
185                 if ( count > 0 )
186                 {
187                     LOGGER.info( "Retrying deployment attempt " + ( count + 1 ) + " of "
188                         + retryFailedDeploymentCounter );
189                 }
190 
191                 deployer.deploy( request, deploymentRepository, artifacts );
192                 exception = null;
193                 break;
194             }
195             catch ( ArtifactDeployerException e )
196             {
197                 if ( count + 1 < retryFailedDeploymentCounter )
198                 {
199                     LOGGER.warn( "Encountered issue during deployment: " + e.getLocalizedMessage() );
200                     LOGGER.debug( e.getMessage() );
201                 }
202                 if ( exception == null )
203                 {
204                     exception = e;
205                 }
206             }
207         }
208         if ( exception != null )
209         {
210             throw exception;
211         }
212     }
213 
214     /**
215      * @param buildingRequest The project building request, must not be <code>null</code>.
216      * @param artifact The artifact for which to create checksums, must not be <code>null</code>.
217      * @throws IOException If the checksums could not be installed.
218      */
219     private void installChecksums( ProjectBuildingRequest buildingRequest, Artifact artifact )
220         throws IOException
221     {
222         File artifactFile = getLocalRepoFile( buildingRequest, artifact );
223         installChecksums( artifactFile );
224     }
225 
226     /**
227      * Installs the checksums for the specified metadata files.
228      *
229      * @param metadataFiles The collection of metadata files to install checksums for, must not be <code>null</code>.
230      * @throws IOException If the checksums could not be installed.
231      */
232     private void installChecksums( Collection<File> metadataFiles )
233         throws IOException
234     {
235         for ( File metadataFile : metadataFiles )
236         {
237             installChecksums( metadataFile );
238         }
239     }
240 
241     /**
242      * Installs the checksums for the specified file (if it exists).
243      *
244      * @param installedFile The path to the already installed file in the local repo for which to generate checksums,
245      *            must not be <code>null</code>.
246      * @throws IOException In case of errors. Could not install checksums.
247      */
248     private void installChecksums( File installedFile )
249         throws IOException
250     {
251         boolean signatureFile = installedFile.getName().endsWith( ".asc" );
252         if ( installedFile.isFile() && !signatureFile )
253         {
254             LOGGER.debug( "Calculating checksums for " + installedFile );
255             digester.calculate( installedFile );
256             installChecksum( installedFile, ".md5", digester.getMd5() );
257             installChecksum( installedFile, ".sha1", digester.getSha1() );
258         }
259     }
260 
261     /**
262      * Installs a checksum for the specified file.
263      *
264      * @param installedFile The base path from which the path to the checksum files is derived by appending the given
265      *            file extension, must not be <code>null</code>.
266      * @param ext The file extension (including the leading dot) to use for the checksum file, must not be
267      *            <code>null</code>.
268      * @param checksum the checksum to write
269      * @throws IOException If the checksum could not be installed.
270      */
271     private void installChecksum( File installedFile, String ext, String checksum )
272         throws IOException
273     {
274         File checksumFile = new File( installedFile.getAbsolutePath() + ext );
275         LOGGER.debug( "Installing checksum to " + checksumFile );
276         try
277         {
278             // noinspection ResultOfMethodCallIgnored
279             checksumFile.getParentFile().mkdirs();
280             FileUtils.fileWrite( checksumFile.getAbsolutePath(), "UTF-8", checksum );
281         }
282         catch ( IOException e )
283         {
284             throw new IOException( "Failed to install checksum to " + checksumFile, e );
285         }
286     }
287 
288     /**
289      * Gets the path of the specified artifact within the local repository. Note that the returned path need not exist
290      * (yet).
291      *
292      * @param buildingRequest The project building request, must not be <code>null</code>.
293      * @param artifact The artifact whose local repo path should be determined, must not be <code>null</code>.
294      * @return The absolute path to the artifact when installed, never <code>null</code>.
295      */
296     private File getLocalRepoFile( ProjectBuildingRequest buildingRequest, Artifact artifact )
297     {
298         String path = repositoryManager.getPathForLocalArtifact( buildingRequest, artifact );
299         return new File( repositoryManager.getLocalRepositoryBasedir( buildingRequest ), path );
300     }
301 
302     /**
303      * Gets the path of the specified artifact metadata within the local repository. Note that the returned path need
304      * not exist (yet).
305      *
306      * @param buildingRequest The project building request, must not be <code>null</code>.
307      * @param metadata The artifact metadata whose local repo path should be determined, must not be <code>null</code>.
308      * @return The absolute path to the artifact metadata when installed, never <code>null</code>.
309      */
310     private File getLocalRepoFile( ProjectBuildingRequest buildingRequest, ArtifactMetadata metadata )
311     {
312         String path = repositoryManager.getPathForLocalMetadata( buildingRequest, metadata );
313         return new File( repositoryManager.getLocalRepositoryBasedir( buildingRequest ), path );
314     }
315 
316 }