View Javadoc

1   package org.apache.maven.plugin.gpg;
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.Iterator;
26  import java.util.List;
27  
28  import org.apache.maven.artifact.Artifact;
29  import org.apache.maven.plugin.MojoExecutionException;
30  import org.apache.maven.plugin.MojoFailureException;
31  import org.apache.maven.project.MavenProject;
32  import org.apache.maven.project.MavenProjectHelper;
33  import org.codehaus.plexus.util.FileUtils;
34  import org.codehaus.plexus.util.SelectorUtils;
35  
36  /**
37   * Sign project artifact, the POM, and attached artifacts with GnuPG for deployment.
38   * 
39   * @author Jason van Zyl
40   * @author Jason Dillon
41   * @author Daniel Kulp
42   * @goal sign
43   * @phase verify
44   * @threadSafe
45   */
46  public class GpgSignAttachedMojo
47      extends AbstractGpgMojo
48  {
49  
50      private static final String DEFAULT_EXCLUDES[] = new String[] { "**/*.md5", "**/*.sha1", "**/*.asc" };
51  
52      /**
53       * Skip doing the gpg signing.
54       * 
55       * @parameter expression="${gpg.skip}" default-value="false"
56       */
57      private boolean skip;
58  
59      /**
60       * A list of files to exclude from being signed. Can contain Ant-style wildcards and double wildcards. The default
61       * excludes are <code>**&#47;*.md5   **&#47;*.sha1    **&#47;*.asc</code>.
62       * 
63       * @parameter
64       * @since 1.0-alpha-4
65       */
66      private String[] excludes;
67  
68      /**
69       * The directory where to store signature files.
70       * 
71       * @parameter default-value="${project.build.directory}/gpg" alias="outputDirectory"
72       * @since 1.0-alpha-4
73       */
74      private File ascDirectory;
75  
76      /**
77       * The maven project.
78       * 
79       * @parameter default-value="${project}"
80       * @required
81       * @readonly
82       */
83      protected MavenProject project;
84  
85      /**
86       * Maven ProjectHelper
87       * 
88       * @component
89       * @required
90       * @readonly
91       */
92      private MavenProjectHelper projectHelper;
93  
94      public void execute()
95          throws MojoExecutionException, MojoFailureException
96      {
97          if ( skip )
98          {
99              // We're skipping the signing stuff
100             return;
101         }
102 
103         if ( excludes == null || excludes.length == 0 )
104         {
105             excludes = DEFAULT_EXCLUDES;
106         }
107         String newExcludes[] = new String[excludes.length];
108         for ( int i = 0; i < excludes.length; i++ )
109         {
110             String pattern;
111             pattern = excludes[i].trim().replace( '/', File.separatorChar ).replace( '\\', File.separatorChar );
112             if ( pattern.endsWith( File.separator ) )
113             {
114                 pattern += "**";
115             }
116             newExcludes[i] = pattern;
117         }
118         excludes = newExcludes;
119 
120         GpgSigner signer = newSigner( project );
121 
122         // ----------------------------------------------------------------------------
123         // What we need to generateSignatureForArtifact here
124         // ----------------------------------------------------------------------------
125 
126         signer.setOutputDirectory( ascDirectory );
127         signer.setBuildDirectory( new File( project.getBuild().getDirectory() ) );
128         signer.setBaseDirectory( project.getBasedir() );
129 
130         List signingBundles = new ArrayList();
131 
132         if ( !"pom".equals( project.getPackaging() ) )
133         {
134             // ----------------------------------------------------------------------------
135             // Project artifact
136             // ----------------------------------------------------------------------------
137 
138             Artifact artifact = project.getArtifact();
139 
140             File file = artifact.getFile();
141 
142             if ( file != null && file.isFile() )
143             {
144                 getLog().debug( "Generating signature for " + file );
145 
146                 File projectArtifactSignature = signer.generateSignatureForArtifact( file );
147 
148                 if ( projectArtifactSignature != null )
149                 {
150                     signingBundles.add( new SigningBundle( artifact.getArtifactHandler().getExtension(),
151                                                            projectArtifactSignature ) );
152                 }
153             }
154             else if ( project.getAttachedArtifacts().isEmpty() )
155             {
156                 throw new MojoFailureException( "The project artifact has not been assembled yet. "
157                     + "Please do not invoke this goal before the lifecycle phase \"package\"." );
158             }
159             else
160             {
161                 getLog().debug( "Main artifact not assembled, skipping signature generation" );
162             }
163         }
164 
165         // ----------------------------------------------------------------------------
166         // POM
167         // ----------------------------------------------------------------------------
168 
169         File pomToSign = new File( project.getBuild().getDirectory(), project.getBuild().getFinalName() + ".pom" );
170 
171         try
172         {
173             FileUtils.copyFile( project.getFile(), pomToSign );
174         }
175         catch ( IOException e )
176         {
177             throw new MojoExecutionException( "Error copying POM for signing.", e );
178         }
179 
180         getLog().debug( "Generating signature for " + pomToSign );
181 
182         File pomSignature = signer.generateSignatureForArtifact( pomToSign );
183 
184         if ( pomSignature != null )
185         {
186             signingBundles.add( new SigningBundle( "pom", pomSignature ) );
187         }
188 
189         // ----------------------------------------------------------------------------
190         // Attached artifacts
191         // ----------------------------------------------------------------------------
192 
193         for ( Iterator i = project.getAttachedArtifacts().iterator(); i.hasNext(); )
194         {
195             Artifact artifact = (Artifact) i.next();
196 
197             File file = artifact.getFile();
198 
199             getLog().debug( "Generating signature for " + file );
200 
201             File signature = signer.generateSignatureForArtifact( file );
202 
203             if ( signature != null )
204             {
205                 signingBundles.add( new SigningBundle( artifact.getArtifactHandler().getExtension(),
206                                                        artifact.getClassifier(), signature ) );
207             }
208         }
209 
210         // ----------------------------------------------------------------------------
211         // Attach all the signatures
212         // ----------------------------------------------------------------------------
213 
214         for ( Iterator i = signingBundles.iterator(); i.hasNext(); )
215         {
216             SigningBundle bundle = (SigningBundle) i.next();
217 
218             projectHelper.attachArtifact( project, bundle.getExtension() + GpgSigner.SIGNATURE_EXTENSION,
219                                           bundle.getClassifier(), bundle.getSignature() );
220         }
221     }
222 
223     /**
224      * Tests whether or not a name matches against at least one exclude pattern.
225      * 
226      * @param name The name to match. Must not be <code>null</code>.
227      * @return <code>true</code> when the name matches against at least one exclude pattern, or <code>false</code>
228      *         otherwise.
229      */
230     protected boolean isExcluded( String name )
231     {
232         for ( int i = 0; i < excludes.length; i++ )
233         {
234             if ( SelectorUtils.matchPath( excludes[i], name ) )
235             {
236                 return true;
237             }
238         }
239         return false;
240     }
241 
242 }