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>**/*.md5 **/*.sha1 **/*.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 }