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