1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  package org.apache.maven.plugins.gpg;
20  
21  import javax.inject.Inject;
22  
23  import java.io.IOException;
24  import java.nio.file.Files;
25  import java.nio.file.InvalidPathException;
26  import java.nio.file.Path;
27  import java.nio.file.Paths;
28  import java.util.ArrayList;
29  import java.util.Arrays;
30  import java.util.Collection;
31  import java.util.Collections;
32  import java.util.HashSet;
33  import java.util.List;
34  import java.util.Map;
35  import java.util.Set;
36  import java.util.stream.Collectors;
37  import java.util.stream.Stream;
38  
39  import org.apache.maven.plugin.MojoExecutionException;
40  import org.apache.maven.plugin.MojoFailureException;
41  import org.apache.maven.plugins.annotations.Mojo;
42  import org.apache.maven.plugins.annotations.Parameter;
43  import org.codehaus.plexus.util.FileUtils;
44  import org.eclipse.aether.DefaultRepositorySystemSession;
45  import org.eclipse.aether.RepositorySystem;
46  import org.eclipse.aether.RepositorySystemSession;
47  import org.eclipse.aether.RequestTrace;
48  import org.eclipse.aether.artifact.Artifact;
49  import org.eclipse.aether.artifact.DefaultArtifact;
50  import org.eclipse.aether.deployment.DeployRequest;
51  import org.eclipse.aether.deployment.DeploymentException;
52  import org.eclipse.aether.repository.LocalRepository;
53  import org.eclipse.aether.repository.RemoteRepository;
54  import org.eclipse.aether.resolution.ArtifactRequest;
55  import org.eclipse.aether.resolution.ArtifactResolutionException;
56  import org.eclipse.aether.resolution.ArtifactResult;
57  import org.eclipse.aether.util.artifact.SubArtifact;
58  
59  
60  
61  
62  
63  
64  
65  
66  @Mojo(name = "sign-deployed", requiresProject = false, threadSafe = true)
67  public class SignDeployedMojo extends AbstractGpgMojo {
68  
69      
70  
71  
72      @Parameter(property = "url", required = true)
73      private String url;
74  
75      
76  
77  
78  
79      @Parameter(property = "repositoryId", required = true)
80      private String repositoryId;
81  
82      
83  
84  
85      @Parameter(property = "javadoc", defaultValue = "true", required = true)
86      private boolean javadoc;
87  
88      
89  
90  
91      @Parameter(property = "sources", defaultValue = "true", required = true)
92      private boolean sources;
93  
94      
95  
96  
97  
98  
99  
100 
101 
102 
103 
104 
105     @Parameter(property = "artifacts")
106     private String artifacts;
107 
108     private final RepositorySystem repositorySystem;
109 
110     private final Map<String, ArtifactCollectorSPI> artifactCollectors;
111 
112     @Inject
113     public SignDeployedMojo(RepositorySystem repositorySystem, Map<String, ArtifactCollectorSPI> artifactCollectors) {
114         this.repositorySystem = repositorySystem;
115         this.artifactCollectors = artifactCollectors;
116     }
117 
118     @Override
119     protected void doExecute() throws MojoExecutionException, MojoFailureException {
120         if (settings.isOffline()) {
121             throw new MojoFailureException("Cannot deploy artifacts when Maven is in offline mode");
122         }
123 
124         Path tempDirectory = null;
125         Set<Artifact> artifacts = new HashSet<>();
126         try {
127             tempDirectory = Files.createTempDirectory("gpg-sign-deployed");
128             getLog().debug("Using temp directory " + tempDirectory);
129 
130             DefaultRepositorySystemSession signingSession =
131                     new DefaultRepositorySystemSession(session.getRepositorySession());
132             signingSession.setLocalRepositoryManager(repositorySystem.newLocalRepositoryManager(
133                     signingSession, new LocalRepository(tempDirectory.toFile())));
134 
135             
136             RemoteRepository deploymentRepository = repositorySystem.newDeploymentRepository(
137                     signingSession, new RemoteRepository.Builder(repositoryId, "default", url).build());
138 
139             
140             getLog().debug("Collecting artifacts for signing...");
141             artifacts.addAll(collectArtifacts(signingSession, deploymentRepository));
142             getLog().info("Collected " + artifacts.size() + " artifact" + ((artifacts.size() > 1) ? "s" : "")
143                     + " for signing");
144 
145             
146             if (sources || javadoc) {
147                 getLog().debug("Adding additional artifacts...");
148                 List<Artifact> additions = new ArrayList<>();
149                 for (Artifact artifact : artifacts) {
150                     if (artifact.getClassifier().isEmpty()) {
151                         if (sources) {
152                             additions.add(new SubArtifact(artifact, "sources", "jar"));
153                         }
154                         if (javadoc) {
155                             additions.add(new SubArtifact(artifact, "javadoc", "jar"));
156                         }
157                     }
158                 }
159                 artifacts.addAll(additions);
160             }
161 
162             
163             getLog().info("Resolving " + artifacts.size() + " artifact" + ((artifacts.size() > 1) ? "s" : "")
164                     + " artifacts for signing...");
165             List<ArtifactResult> results = repositorySystem.resolveArtifacts(
166                     signingSession,
167                     artifacts.stream()
168                             .map(a -> new ArtifactRequest(a, Collections.singletonList(deploymentRepository), "gpg"))
169                             .collect(Collectors.toList()));
170             artifacts = results.stream().map(ArtifactResult::getArtifact).collect(Collectors.toSet());
171 
172             
173             AbstractGpgSigner signer = newSigner(null);
174             signer.setOutputDirectory(tempDirectory.toFile());
175             getLog().info("Signer '" + signer.signerName() + "' is signing " + artifacts.size() + " file"
176                     + ((artifacts.size() > 1) ? "s" : "") + " with key " + signer.getKeyInfo());
177 
178             HashSet<Artifact> signatures = new HashSet<>();
179             for (Artifact a : artifacts) {
180                 signatures.add(new DefaultArtifact(
181                                 a.getGroupId(),
182                                 a.getArtifactId(),
183                                 a.getClassifier(),
184                                 a.getExtension() + AbstractGpgSigner.SIGNATURE_EXTENSION,
185                                 a.getVersion())
186                         .setFile(signer.generateSignatureForArtifact(a.getFile())));
187             }
188 
189             
190             getLog().info("Deploying artifact signatures...");
191             repositorySystem.deploy(
192                     signingSession,
193                     new DeployRequest()
194                             .setRepository(deploymentRepository)
195                             .setArtifacts(signatures)
196                             .setTrace(RequestTrace.newChild(null, this)));
197         } catch (IOException e) {
198             throw new MojoExecutionException("IO error: " + e.getMessage(), e);
199         } catch (ArtifactResolutionException e) {
200             throw new MojoExecutionException(
201                     "Error resolving deployed artifacts " + artifacts + ": " + e.getMessage(), e);
202         } catch (DeploymentException e) {
203             throw new MojoExecutionException("Error deploying signatures: " + e.getMessage(), e);
204         } finally {
205             if (tempDirectory != null) {
206                 getLog().info("Cleaning up...");
207                 try {
208                     FileUtils.deleteDirectory(tempDirectory.toFile());
209                 } catch (IOException e) {
210                     getLog().warn("Could not clean up temp directory " + tempDirectory);
211                 }
212             }
213         }
214     }
215 
216     
217 
218 
219 
220     protected Collection<Artifact> collectArtifacts(RepositorySystemSession session, RemoteRepository remoteRepository)
221             throws IOException {
222         Collection<Artifact> result = null;
223         for (ArtifactCollectorSPI artifactCollector : artifactCollectors.values()) {
224             result = artifactCollector.collectArtifacts(session, remoteRepository);
225             if (result != null) {
226                 break;
227             }
228         }
229         if (result == null) {
230             if (artifacts != null) {
231                 try {
232                     Path path = Paths.get(artifacts);
233                     if (Files.isRegularFile(path)) {
234                         try (Stream<String> lines = Files.lines(path)) {
235                             result = lines.filter(l -> !l.isEmpty() && !l.startsWith("#"))
236                                     .map(DefaultArtifact::new)
237                                     .collect(Collectors.toSet());
238                         }
239                     }
240                 } catch (InvalidPathException e) {
241                     
242                 }
243                 if (result == null) {
244                     result = Arrays.stream(artifacts.split(","))
245                             .map(DefaultArtifact::new)
246                             .collect(Collectors.toSet());
247                 }
248             }
249         }
250         if (result == null) {
251             throw new IllegalStateException("No source to collect from (set -Dartifacts=g:a:v... or add collector)");
252         }
253         return result;
254     }
255 }