Skip to content

Commit 58fa21e

Browse files
committed
build-sys: Rework vendoring for source archive
In preparation for vendoring composefs-rs from git. Basically before, things work fine when we're just vendoring from crates.io, but fall over when we add a git dependency. The Fedora `cargo_prep` macro writes a hardcoded `.cargo/config.toml` which only has a replacement for `crates.io`, but we need the generated replacement for git too which is output by `cargo vendor-filterer` - which previously we were discarding. This was surprisingly difficult! - Capture the output of `vendor-filterer` - Work around a bug where it puts a broken `directory` path in the generated TOML - Insert that as a new `vendor-config.toml` in our source - Do use `cargo_prep` to init the RPM config in the spec, but re-inject our vendor config appended to that one. Signed-off-by: Colin Walters <[email protected]>
1 parent a2a5a7c commit 58fa21e

File tree

4 files changed

+64
-38
lines changed

4 files changed

+64
-38
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

contrib/packaging/bootc.spec

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,11 @@ Provides: ostree-cli(ostree-container)
6464

6565
%prep
6666
%autosetup -p1 -a1
67-
%cargo_prep -v vendor
67+
# Default -v vendor config doesn't support non-crates.io deps (i.e. git)
68+
cp .cargo/vendor-config.toml .
69+
%cargo_prep -N
70+
cat vendor-config.toml >> .cargo/config.toml
71+
rm vendor-config.toml
6872

6973
%build
7074
%if 0%{?fedora} || 0%{?rhel} >= 10
@@ -74,6 +78,8 @@ Provides: ostree-cli(ostree-container)
7478
%endif
7579

7680
%cargo_vendor_manifest
81+
# https://pagure.io/fedora-rust/rust-packaging/issue/33
82+
sed -i -e '/https:\/\//d' cargo-vendor.txt
7783
%cargo_license_summary
7884
%{cargo_license} > LICENSE.dependencies
7985

xtask/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ anyhow = { workspace = true }
1616
camino = { workspace = true }
1717
chrono = { workspace = true, features = ["std"] }
1818
fn-error-context = { workspace = true }
19+
tar = "0.4"
20+
toml = "0.8"
1921
tempfile = { workspace = true }
2022
mandown = "0.1.3"
2123
xshell = { version = "0.2.6" }

xtask/src/xtask.rs

Lines changed: 53 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
44
use std::fs::File;
55
use std::io::{BufRead, BufReader, BufWriter, Write};
6-
use std::process::{Command, Stdio};
6+
use std::process::Command;
77

88
use anyhow::{anyhow, Context, Result};
99
use camino::{Utf8Path, Utf8PathBuf};
@@ -16,6 +16,13 @@ const TEST_IMAGES: &[&str] = &[
1616
"quay.io/curl/curl:latest",
1717
"registry.access.redhat.com/ubi9/podman:latest",
1818
];
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+
];
1926

2027
fn main() {
2128
if let Err(e) = try_main() {
@@ -261,6 +268,23 @@ fn git_source_date_epoch(dir: &Utf8Path) -> Result<u64> {
261268
Ok(r)
262269
}
263270

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+
264288
#[context("Packaging")]
265289
fn impl_package(sh: &Shell) -> Result<Package> {
266290
let source_date_epoch = git_source_date_epoch(".".into())?;
@@ -269,48 +293,40 @@ fn impl_package(sh: &Shell) -> Result<Package> {
269293

270294
let namev = format!("{NAME}-{v}");
271295
let p = Utf8Path::new("target").join(format!("{namev}.tar"));
272-
let o = File::create(&p)?;
273296
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.
308300
let vendorpath = Utf8Path::new("target").join(format!("{namev}-vendor.tar.zstd"));
309-
cmd!(
301+
let vendor_config = cmd!(
310302
sh,
311303
"cargo vendor-filterer --prefix=vendor --format=tar.zstd {vendorpath}"
312304
)
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+
)
313325
.run()?;
326+
// Compress with zstd
327+
let srcpath: Utf8PathBuf = format!("{p}.zstd").into();
328+
cmd!(sh, "zstd --rm -f {p} -o {srcpath}").run()?;
329+
314330
Ok(Package {
315331
version: v,
316332
srcpath,

0 commit comments

Comments
 (0)