22
22
import com .facebook .buck .model .UnflavoredBuildTarget ;
23
23
import com .facebook .buck .rules .BuildRule ;
24
24
import com .facebook .buck .rules .SourcePathResolver ;
25
+ import com .facebook .buck .util .Ansi ;
26
+ import com .facebook .buck .util .Console ;
27
+ import com .facebook .buck .util .DefaultProcessExecutor ;
28
+ import com .facebook .buck .util .HumanReadableException ;
29
+ import com .facebook .buck .util .ProcessExecutor ;
30
+ import com .facebook .buck .util .ProcessExecutorParams ;
31
+ import com .facebook .buck .util .Verbosity ;
25
32
import com .google .common .base .Joiner ;
26
33
import com .google .common .base .Preconditions ;
27
34
import com .google .common .base .StandardSystemProperty ;
45
52
import org .eclipse .aether .spi .locator .ServiceLocator ;
46
53
import org .eclipse .aether .util .artifact .SubArtifact ;
47
54
55
+ import java .io .ByteArrayOutputStream ;
48
56
import java .io .File ;
49
57
import java .io .IOException ;
58
+ import java .io .PrintStream ;
50
59
import java .net .MalformedURLException ;
51
60
import java .net .URL ;
52
61
import java .nio .file .Path ;
@@ -68,20 +77,12 @@ public class Publisher {
68
77
}
69
78
private static final Logger LOG = Logger .get (Publisher .class );
70
79
80
+ private final Optional <String > pgpPassphrase ;
71
81
private final ServiceLocator locator ;
72
82
private final LocalRepository localRepo ;
73
83
private final RemoteRepository remoteRepo ;
74
84
private final boolean dryRun ;
75
85
76
- public Publisher (
77
- ProjectFilesystem repositoryFilesystem ,
78
- Optional <URL > remoteRepoUrl ,
79
- Optional <String > username ,
80
- Optional <String > password ,
81
- boolean dryRun ) {
82
- this (repositoryFilesystem .getRootPath (), remoteRepoUrl , username , password , dryRun );
83
- }
84
-
85
86
/**
86
87
* @param localRepoPath Typically obtained as
87
88
* {@link com.facebook.buck.io.ProjectFilesystem#getRootPath}
@@ -90,23 +91,25 @@ public Publisher(
90
91
* constructed {@link DeployRequest}. No actual publishing will happen
91
92
*/
92
93
public Publisher (
93
- Path localRepoPath ,
94
+ ProjectFilesystem localRepoPath ,
94
95
Optional <URL > remoteRepoUrl ,
95
96
Optional <String > username ,
96
97
Optional <String > password ,
98
+ Optional <String > pgpPassphrase ,
97
99
boolean dryRun ) {
98
- this .localRepo = new LocalRepository (localRepoPath .toFile ());
100
+ this .localRepo = new LocalRepository (localRepoPath .getRootPath (). toFile ());
99
101
this .remoteRepo = AetherUtil .toRemoteRepository (
100
102
remoteRepoUrl .orElse (MAVEN_CENTRAL ),
101
103
username ,
102
104
password );
105
+ this .pgpPassphrase = pgpPassphrase ;
103
106
this .locator = AetherUtil .initServiceLocator ();
104
107
this .dryRun = dryRun ;
105
108
}
106
109
107
110
public ImmutableSet <DeployResult > publish (
108
111
SourcePathResolver pathResolver ,
109
- ImmutableSet <MavenPublishable > publishables ) throws DeploymentException {
112
+ ImmutableSet <MavenPublishable > publishables ) throws DeploymentException , InterruptedException {
110
113
ImmutableListMultimap <UnflavoredBuildTarget , UnflavoredBuildTarget > duplicateBuiltinBuileRules =
111
114
checkForDuplicatePackagedDeps (publishables );
112
115
if (duplicateBuiltinBuileRules .size () > 0 ) {
@@ -198,7 +201,7 @@ public DeployResult publish(
198
201
String artifactId ,
199
202
String version ,
200
203
List <File > toPublish )
201
- throws DeploymentException {
204
+ throws DeploymentException , InterruptedException {
202
205
return publish (new DefaultArtifact (groupId , artifactId , "" , version ), toPublish );
203
206
}
204
207
@@ -211,7 +214,7 @@ public DeployResult publish(
211
214
* extension of each given file will be used as a maven "extension" coordinate
212
215
*/
213
216
public DeployResult publish (Artifact descriptor , List <File > toPublish )
214
- throws DeploymentException {
217
+ throws DeploymentException , InterruptedException {
215
218
String providedExtension = descriptor .getExtension ();
216
219
if (!providedExtension .isEmpty ()) {
217
220
LOG .warn (
@@ -236,7 +239,7 @@ public DeployResult publish(Artifact descriptor, List<File> toPublish)
236
239
* coordinates in the corresponding {@link Artifact}.
237
240
* @see Artifact#setFile
238
241
*/
239
- public DeployResult publish (List <Artifact > toPublish ) throws DeploymentException {
242
+ public DeployResult publish (List <Artifact > toPublish ) throws DeploymentException , InterruptedException {
240
243
RepositorySystem repoSys = Preconditions .checkNotNull (
241
244
locator .getService (RepositorySystem .class ));
242
245
@@ -255,15 +258,63 @@ public DeployResult publish(List<Artifact> toPublish) throws DeploymentException
255
258
}
256
259
}
257
260
258
- private DeployRequest createDeployRequest (List <Artifact > toPublish ) {
261
+ private DeployRequest createDeployRequest (List <Artifact > toPublish ) throws InterruptedException {
259
262
DeployRequest deployRequest = new DeployRequest ().setRepository (remoteRepo );
260
263
for (Artifact artifact : toPublish ) {
261
264
File file = artifact .getFile ();
262
265
Preconditions .checkNotNull (file );
263
266
Preconditions .checkArgument (file .exists (), "No such file: %s" , file .getAbsolutePath ());
264
267
265
268
deployRequest .addArtifact (artifact );
269
+
270
+ if (pgpPassphrase .isPresent ()) {
271
+ deployRequest .addArtifact (sign (artifact , file ));
272
+ }
266
273
}
267
274
return deployRequest ;
268
275
}
276
+
277
+ private SubArtifact sign (Artifact descriptor , File file ) throws InterruptedException {
278
+ // Run gpg
279
+ try (PrintStream stdout = new PrintStream (new ByteArrayOutputStream ());
280
+ PrintStream stderr = new PrintStream (new ByteArrayOutputStream ())) {
281
+ File expectedOutput = new File (file .getAbsolutePath () + ".asc" );
282
+ if (expectedOutput .exists () && !expectedOutput .delete ()) {
283
+ throw new HumanReadableException (
284
+ "Existing signature exists, but cannot be deleted: %s" ,
285
+ file );
286
+ }
287
+
288
+ ProcessExecutor processExecutor = new DefaultProcessExecutor (
289
+ new Console (
290
+ Verbosity .SILENT ,
291
+ stdout ,
292
+ stderr ,
293
+ Ansi .withoutTty ()));
294
+ ProcessExecutorParams args = ProcessExecutorParams .builder ()
295
+ .addCommand (
296
+ "gpg" ,
297
+ "-ab" ,
298
+ "--batch" ,
299
+ "--passphrase" , pgpPassphrase .get (),
300
+ file .getAbsolutePath ())
301
+ .build ();
302
+ ProcessExecutor .Result result = processExecutor .launchAndExecute (args );
303
+ if (result .getExitCode () != 0 ) {
304
+ throw new HumanReadableException ("Unable to sign %s" , file );
305
+ }
306
+
307
+ if (!expectedOutput .exists ()) {
308
+ throw new HumanReadableException ("Unable to find signature for %s" , file );
309
+ }
310
+
311
+ return new SubArtifact (
312
+ descriptor ,
313
+ descriptor .getClassifier (),
314
+ "*.asc" ,
315
+ expectedOutput );
316
+ } catch (IOException e ) {
317
+ throw new HumanReadableException (e , "Unable to generate signauture for %s" , file );
318
+ }
319
+ }
269
320
}
0 commit comments