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                 // installChecksums( buildingRequest, artifact, createChecksum );
112             }
113             else if ( !attachedArtifacts.isEmpty() )
114             {
115                 // TODO: Reconsider this exception? Better Exception type?
116                 throw new NoFileAssignedException( "The packaging plugin for this project did not assign "
117                     + "a main file to the project but it has attachments. Change packaging to 'pom'." );
118             }
119             else
120             {
121                 // TODO: Reconsider this exception? Better Exception type?
122                 throw new NoFileAssignedException( "The packaging for this project did not assign "
123                     + "a file to the build artifact" );
124             }
125         }
126 
127         for ( Artifact attached : attachedArtifacts )
128         {
129             // installChecksums( buildingRequest, artifact, createChecksum );
130             deployableArtifacts.add( attached );
131         }
132 
133         installChecksumsForAllArtifacts( buildingRequest, deployableArtifacts );
134         deploy( buildingRequest, deployableArtifacts, artifactRepository, retryFailedDeploymentCount );
135     }
136 
137     private void validateParameters( ProjectBuildingRequest buildingRequest,
138                                      ProjectDeployerRequest projectDeployerRequest,
139                                      ArtifactRepository artifactRepository )
140     {
141         if ( buildingRequest == null )
142         {
143             throw new IllegalArgumentException( "The parameter buildingRequest is not allowed to be null." );
144         }
145         if ( projectDeployerRequest == null )
146         {
147             throw new IllegalArgumentException( "The parameter projectDeployerRequest is not allowed to be null." );
148         }
149         if ( artifactRepository == null )
150         {
151             throw new IllegalArgumentException( "The parameter artifactRepository is not allowed to be null." );
152         }
153     }
154 
155     private void installChecksumsForAllArtifacts( ProjectBuildingRequest request, Collection<Artifact> artifacts )
156     {
157         for ( Artifact item : artifacts )
158         {
159             try
160             {
161                 LOGGER.debug( "Installing checksum for " + item.getId() );
162                 installChecksums( request, item );
163             }
164             catch ( IOException e )
165             {
166                 // THINK HARD ABOUT IT
167                 LOGGER.error( "Failure during checksum generation for " + item.getId() );
168             }
169         }
170     }
171 
172     private void deploy( ProjectBuildingRequest request, Collection<Artifact> artifacts,
173                          ArtifactRepository deploymentRepository, int retryFailedDeploymentCount )
174         throws ArtifactDeployerException
175     {
176 
177         // for now retry means redeploy the complete artifacts collection
178         int retryFailedDeploymentCounter = Math.max( 1, Math.min( 10, retryFailedDeploymentCount ) );
179         ArtifactDeployerException exception = null;
180         for ( int count = 0; count < retryFailedDeploymentCounter; count++ )
181         {
182             try
183             {
184                 if ( count > 0 )
185                 {
186                     LOGGER.info( "Retrying deployment attempt " + ( count + 1 ) + " of "
187                         + retryFailedDeploymentCounter );
188                 }
189 
190                 deployer.deploy( request, deploymentRepository, artifacts );
191                 exception = null;
192                 break;
193             }
194             catch ( ArtifactDeployerException e )
195             {
196                 if ( count + 1 < retryFailedDeploymentCounter )
197                 {
198                     LOGGER.warn( "Encountered issue during deployment: " + e.getLocalizedMessage() );
199                     LOGGER.debug( e.getMessage() );
200                 }
201                 if ( exception == null )
202                 {
203                     exception = e;
204                 }
205             }
206         }
207         if ( exception != null )
208         {
209             throw exception;
210         }
211     }
212 
213     /**
214      * @param buildingRequest The project building request, must not be <code>null</code>.
215      * @param artifact The artifact for which to create checksums, must not be <code>null</code>.
216      * @param createChecksum {@code true} if checksum should be created, otherwise {@code false}.
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 }