View Javadoc
1   package org.apache.maven.shared.project.install.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.Collection;
25  import java.util.Collections;
26  import java.util.LinkedHashSet;
27  import java.util.List;
28  
29  import org.apache.maven.artifact.Artifact;
30  import org.apache.maven.artifact.metadata.ArtifactMetadata;
31  import org.apache.maven.project.MavenProject;
32  import org.apache.maven.project.ProjectBuildingRequest;
33  import org.apache.maven.project.artifact.ProjectArtifact;
34  import org.apache.maven.project.artifact.ProjectArtifactMetadata;
35  import org.apache.maven.shared.artifact.install.ArtifactInstaller;
36  import org.apache.maven.shared.artifact.install.ArtifactInstallerException;
37  import org.apache.maven.shared.project.NoFileAssignedException;
38  import org.apache.maven.shared.project.install.ProjectInstaller;
39  import org.apache.maven.shared.project.install.ProjectInstallerRequest;
40  import org.apache.maven.shared.repository.RepositoryManager;
41  import org.codehaus.plexus.component.annotations.Component;
42  import org.codehaus.plexus.component.annotations.Requirement;
43  import org.codehaus.plexus.util.FileUtils;
44  import org.slf4j.Logger;
45  import org.slf4j.LoggerFactory;
46  
47  /**
48   * This will install a whole project into the appropriate repository.
49   * 
50   * @author Karl Heinz Marbaise <a href="mailto:khmarbaise@apache.org">khmarbaise@apache.org</a>
51   */
52  @Component( role = ProjectInstaller.class )
53  public class DefaultProjectInstaller
54      implements ProjectInstaller
55  {
56  
57      private static final Logger LOGGER = LoggerFactory.getLogger( DefaultProjectInstaller.class );
58  
59      @Requirement
60      private ArtifactInstaller installer;
61  
62      @Requirement
63      private RepositoryManager repositoryManager;
64  
65      private final DualDigester digester = new DualDigester();
66  
67      /**
68       * {@inheritDoc}
69       */
70      @Override
71      public void install( ProjectBuildingRequest buildingRequest, ProjectInstallerRequest request )
72          throws IOException, ArtifactInstallerException, NoFileAssignedException
73      {
74  
75          MavenProject project = request.getProject();
76          boolean createChecksum = request.isCreateChecksum();
77          boolean updateReleaseInfo = request.isUpdateReleaseInfo();
78  
79          Artifact artifact = project.getArtifact();
80          String packaging = project.getPackaging();
81          File pomFile = project.getFile();
82  
83          List<Artifact> attachedArtifacts = project.getAttachedArtifacts();
84  
85          // TODO: push into transformation
86          boolean isPomArtifact = "pom".equals( packaging );
87  
88          ProjectArtifactMetadata metadata;
89  
90          if ( updateReleaseInfo )
91          {
92              artifact.setRelease( true );
93          }
94  
95          Collection<File> metadataFiles = new LinkedHashSet<File>();
96  
97          if ( isPomArtifact )
98          {
99              if ( pomFile != null )
100             {
101                 installer.install( buildingRequest,
102                                    Collections.<Artifact>singletonList( new ProjectArtifact( project ) ) );
103                 installChecksums( buildingRequest, artifact, createChecksum );
104                 addMetaDataFilesForArtifact( buildingRequest, artifact, metadataFiles, createChecksum );
105             }
106         }
107         else
108         {
109             if ( pomFile != null )
110             {
111                 metadata = new ProjectArtifactMetadata( artifact, pomFile );
112                 artifact.addMetadata( metadata );
113             }
114 
115             File file = artifact.getFile();
116 
117             // Here, we have a temporary solution to MINSTALL-3 (isDirectory() is true if it went through compile
118             // but not package). We are designing in a proper solution for Maven 2.1
119             if ( file != null && file.isFile() )
120             {
121                 installer.install( buildingRequest, Collections.<Artifact>singletonList( artifact ) );
122                 installChecksums( buildingRequest, artifact, createChecksum );
123                 addMetaDataFilesForArtifact( buildingRequest, artifact, metadataFiles, createChecksum );
124             }
125             else if ( !attachedArtifacts.isEmpty() )
126             {
127                 throw new NoFileAssignedException( "The packaging plugin for this project did not assign "
128                     + "a main file to the project but it has attachments. Change packaging to 'pom'." );
129             }
130             else
131             {
132                 // CHECKSTYLE_OFF: LineLength
133                 throw new NoFileAssignedException( "The packaging for this project did not assign a file to the build artifact" );
134                 // CHECKSTYLE_ON: LineLength
135             }
136         }
137 
138         for ( Artifact attached : attachedArtifacts )
139         {
140             installer.install( buildingRequest, Collections.singletonList( attached ) );
141             installChecksums( buildingRequest, attached, createChecksum );
142             addMetaDataFilesForArtifact( buildingRequest, attached, metadataFiles, createChecksum );
143         }
144 
145         installChecksums( metadataFiles );
146     }
147 
148     /**
149      * Installs the checksums for the specified artifact if this has been enabled in the plugin configuration. This
150      * method creates checksums for files that have already been installed to the local repo to account for on-the-fly
151      * generated/updated files. For example, in Maven 2.0.4- the <code>ProjectArtifactMetadata</code> did not install
152      * the original POM file (cf. MNG-2820). While the plugin currently requires Maven 2.0.6, we continue to hash the
153      * installed POM for robustness with regard to future changes like re-introducing some kind of POM filtering.
154      *
155      * @param buildingRequest The project building request, must not be <code>null</code>.
156      * @param artifact The artifact for which to create checksums, must not be <code>null</code>.
157      * @param createChecksum {@code true} if checksum should be created, otherwise {@code false}.
158      * @throws IOException If the checksums could not be installed.
159      */
160     private void installChecksums( ProjectBuildingRequest buildingRequest, Artifact artifact, boolean createChecksum )
161         throws IOException
162     {
163         if ( !createChecksum )
164         {
165             return;
166         }
167 
168         File artifactFile = getLocalRepoFile( buildingRequest, artifact );
169         installChecksums( artifactFile );
170     }
171 
172     // CHECKSTYLE_OFF: LineLength
173     private void addMetaDataFilesForArtifact( ProjectBuildingRequest buildingRequest, Artifact artifact,
174                                               Collection<File> targetMetadataFiles, boolean createChecksum )
175     // CHECKSTYLE_ON: LineLength
176     {
177         if ( !createChecksum )
178         {
179             return;
180         }
181 
182         Collection<ArtifactMetadata> metadatas = artifact.getMetadataList();
183         if ( metadatas != null )
184         {
185             for ( ArtifactMetadata metadata : metadatas )
186             {
187                 File metadataFile = getLocalRepoFile( buildingRequest, metadata );
188                 targetMetadataFiles.add( metadataFile );
189             }
190         }
191     }
192 
193     /**
194      * Installs the checksums for the specified metadata files.
195      *
196      * @param metadataFiles The collection of metadata files to install checksums for, must not be <code>null</code>.
197      * @throws IOException If the checksums could not be installed.
198      */
199     private void installChecksums( Collection<File> metadataFiles )
200         throws IOException
201     {
202         for ( File metadataFile : metadataFiles )
203         {
204             installChecksums( metadataFile );
205         }
206     }
207 
208     /**
209      * Installs the checksums for the specified file (if it exists).
210      *
211      * @param installedFile The path to the already installed file in the local repo for which to generate checksums,
212      *            must not be <code>null</code>.
213      * @throws IOException In case of errors. Could not install checksums.
214      */
215     private void installChecksums( File installedFile )
216         throws IOException
217     {
218         boolean signatureFile = installedFile.getName().endsWith( ".asc" );
219         if ( installedFile.isFile() && !signatureFile )
220         {
221             LOGGER.debug( "Calculating checksums for " + installedFile );
222             digester.calculate( installedFile );
223             installChecksum( installedFile, ".md5", digester.getMd5() );
224             installChecksum( installedFile, ".sha1", digester.getSha1() );
225         }
226     }
227 
228     /**
229      * Installs a checksum for the specified file.
230      *
231      * @param installedFile The base path from which the path to the checksum files is derived by appending the given
232      *            file extension, must not be <code>null</code>.
233      * @param ext The file extension (including the leading dot) to use for the checksum file, must not be
234      *            <code>null</code>.
235      * @param checksum the checksum to write
236      * @throws IOException If the checksum could not be installed.
237      */
238     private void installChecksum( File installedFile, String ext, String checksum )
239         throws IOException
240     {
241         File checksumFile = new File( installedFile.getAbsolutePath() + ext );
242         LOGGER.debug( "Installing checksum to " + checksumFile );
243         try
244         {
245             // noinspection ResultOfMethodCallIgnored
246             checksumFile.getParentFile().mkdirs();
247             FileUtils.fileWrite( checksumFile.getAbsolutePath(), "UTF-8", checksum );
248         }
249         catch ( IOException e )
250         {
251             throw new IOException( "Failed to install checksum to " + checksumFile, e );
252         }
253     }
254 
255     /**
256      * Gets the path of the specified artifact within the local repository. Note that the returned path need not exist
257      * (yet).
258      *
259      * @param buildingRequest The project building request, must not be <code>null</code>.
260      * @param artifact The artifact whose local repo path should be determined, must not be <code>null</code>.
261      * @return The absolute path to the artifact when installed, never <code>null</code>.
262      */
263     private File getLocalRepoFile( ProjectBuildingRequest buildingRequest, Artifact artifact )
264     {
265         String path = repositoryManager.getPathForLocalArtifact( buildingRequest, artifact );
266         return new File( repositoryManager.getLocalRepositoryBasedir( buildingRequest ), path );
267     }
268 
269     /**
270      * Gets the path of the specified artifact metadata within the local repository. Note that the returned path need
271      * not exist (yet).
272      *
273      * @param buildingRequest The project building request, must not be <code>null</code>.
274      * @param metadata The artifact metadata whose local repo path should be determined, must not be <code>null</code>.
275      * @return The absolute path to the artifact metadata when installed, never <code>null</code>.
276      */
277     private File getLocalRepoFile( ProjectBuildingRequest buildingRequest, ArtifactMetadata metadata )
278     {
279         String path = repositoryManager.getPathForLocalMetadata( buildingRequest, metadata );
280         return new File( repositoryManager.getLocalRepositoryBasedir( buildingRequest ), path );
281     }
282 
283 }