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