3
3
4
4
use std:: fs:: File ;
5
5
use std:: io:: { BufRead , BufReader , BufWriter , Write } ;
6
- use std:: process:: { Command , Stdio } ;
6
+ use std:: process:: Command ;
7
7
8
8
use anyhow:: { anyhow, Context , Result } ;
9
9
use camino:: { Utf8Path , Utf8PathBuf } ;
@@ -16,6 +16,13 @@ const TEST_IMAGES: &[&str] = &[
16
16
"quay.io/curl/curl:latest" ,
17
17
"registry.access.redhat.com/ubi9/podman:latest" ,
18
18
] ;
19
+ const TAR_REPRODUCIBLE_OPTS : & [ & str ] = & [
20
+ "--sort=name" ,
21
+ "--owner=0" ,
22
+ "--group=0" ,
23
+ "--numeric-owner" ,
24
+ "--pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime" ,
25
+ ] ;
19
26
20
27
fn main ( ) {
21
28
if let Err ( e) = try_main ( ) {
@@ -261,6 +268,23 @@ fn git_source_date_epoch(dir: &Utf8Path) -> Result<u64> {
261
268
Ok ( r)
262
269
}
263
270
271
+ /// When using cargo-vendor-filterer --format=tar, the config generated has a bogus source
272
+ /// directory. This edits it to refer to vendor/ as a stable relative reference.
273
+ #[ context( "Editing vendor config" ) ]
274
+ fn edit_vendor_config ( config : & str ) -> Result < String > {
275
+ let mut config: toml:: Value = toml:: from_str ( config) ?;
276
+ let config = config. as_table_mut ( ) . unwrap ( ) ;
277
+ let source_table = config. get_mut ( "source" ) . unwrap ( ) ;
278
+ let source_table = source_table. as_table_mut ( ) . unwrap ( ) ;
279
+ let vendored_sources = source_table. get_mut ( "vendored-sources" ) . unwrap ( ) ;
280
+ let vendored_sources = vendored_sources. as_table_mut ( ) . unwrap ( ) ;
281
+ let previous =
282
+ vendored_sources. insert ( "directory" . into ( ) , toml:: Value :: String ( "vendor" . into ( ) ) ) ;
283
+ assert ! ( previous. is_some( ) ) ;
284
+
285
+ Ok ( config. to_string ( ) )
286
+ }
287
+
264
288
#[ context( "Packaging" ) ]
265
289
fn impl_package ( sh : & Shell ) -> Result < Package > {
266
290
let source_date_epoch = git_source_date_epoch ( "." . into ( ) ) ?;
@@ -269,48 +293,40 @@ fn impl_package(sh: &Shell) -> Result<Package> {
269
293
270
294
let namev = format ! ( "{NAME}-{v}" ) ;
271
295
let p = Utf8Path :: new ( "target" ) . join ( format ! ( "{namev}.tar" ) ) ;
272
- let o = File :: create ( & p) ?;
273
296
let prefix = format ! ( "{namev}/" ) ;
274
- let st = Command :: new ( "git" )
275
- . args ( [
276
- "archive" ,
277
- "--format=tar" ,
278
- "--prefix" ,
279
- prefix. as_str ( ) ,
280
- "HEAD" ,
281
- ] )
282
- . stdout ( Stdio :: from ( o) )
283
- . status ( ) ?;
284
- if !st. success ( ) {
285
- anyhow:: bail!( "Failed to run {st:?}" ) ;
286
- }
287
- let st = Command :: new ( "tar" )
288
- . args ( [
289
- "-r" ,
290
- "-C" ,
291
- "target" ,
292
- "--sort=name" ,
293
- "--owner=0" ,
294
- "--group=0" ,
295
- "--numeric-owner" ,
296
- "--pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime" ,
297
- ] )
298
- . arg ( format ! ( "--transform=s,^,{prefix}," ) )
299
- . arg ( format ! ( "--mtime=@{source_date_epoch}" ) )
300
- . args ( [ "-f" , p. as_str ( ) , "man" ] )
301
- . status ( )
302
- . context ( "Failed to execute tar" ) ?;
303
- if !st. success ( ) {
304
- anyhow:: bail!( "Failed to run {st:?}" ) ;
305
- }
306
- let srcpath: Utf8PathBuf = format ! ( "{p}.zstd" ) . into ( ) ;
307
- cmd ! ( sh, "zstd --rm -f {p} -o {srcpath}" ) . run ( ) ?;
297
+ cmd ! ( sh, "git archive --format=tar --prefix={prefix} -o {p} HEAD" ) . run ( ) ?;
298
+ // Generate the vendor directory now, as we want to embed the generated config to use
299
+ // it in our source.
308
300
let vendorpath = Utf8Path :: new ( "target" ) . join ( format ! ( "{namev}-vendor.tar.zstd" ) ) ;
309
- cmd ! (
301
+ let vendor_config = cmd ! (
310
302
sh,
311
303
"cargo vendor-filterer --prefix=vendor --format=tar.zstd {vendorpath}"
312
304
)
305
+ . read ( ) ?;
306
+ let vendor_config = edit_vendor_config ( & vendor_config) ?;
307
+ // Append .cargo/vendor-config.toml (a made up filename) into the tar archive.
308
+ {
309
+ let tmpdir = tempfile:: tempdir_in ( "target" ) ?;
310
+ let tmpdir_path = tmpdir. path ( ) ;
311
+ let path = tmpdir_path. join ( "vendor-config.toml" ) ;
312
+ std:: fs:: write ( & path, vendor_config) ?;
313
+ let source_date_epoch = format ! ( "{source_date_epoch}" ) ;
314
+ cmd ! (
315
+ sh,
316
+ "tar -r -C {tmpdir_path} {TAR_REPRODUCIBLE_OPTS...} --mtime=@{source_date_epoch} --transform=s,^,{prefix}.cargo/, -f {p} vendor-config.toml"
317
+ )
318
+ . run ( ) ?;
319
+ }
320
+ // Append our generated man pages.
321
+ cmd ! (
322
+ sh,
323
+ "tar -r -C target {TAR_REPRODUCIBLE_OPTS...} --transform=s,^,{prefix}, -f {p} man"
324
+ )
313
325
. run ( ) ?;
326
+ // Compress with zstd
327
+ let srcpath: Utf8PathBuf = format ! ( "{p}.zstd" ) . into ( ) ;
328
+ cmd ! ( sh, "zstd --rm -f {p} -o {srcpath}" ) . run ( ) ?;
329
+
314
330
Ok ( Package {
315
331
version : v,
316
332
srcpath,
0 commit comments