Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework vendoring #846

Merged
merged 4 commits into from
Feb 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 10 additions & 12 deletions contrib/packaging/bootupd.spec
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

%global crate bootupd

Name: bootupd
Name: rust-%{crate}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will not create a big issue in Fedora/RHEL? Changing the package name?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just the source name, and it's already named this in Fedora https://src.fedoraproject.org/rpms/rust-bootupd but it isn't in RHEL https://gitlab.com/redhat/centos-stream/rpms/bootupd

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #838 which introduced this change

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IOW, one pain point we are going to need to eat here is that because it'd be hugely painful (AFAIK) to rename the source package in RHEL, we will have spec file divergence for the forseeable future there.

Version: 0.2.9
Release: 1%{?dist}
Summary: Bootloader updater

License: Apache-2.0
URL: https://github.com/coreos/bootupd
Source0: %{url}/releases/download/v%{version}/bootupd-%{version}.crate
Source0: %{url}/releases/download/v%{version}/bootupd-%{version}.tar.zstd
Source1: %{url}/releases/download/v%{version}/bootupd-%{version}-vendor.tar.zstd
ExcludeArch: %{ix86}

Expand Down Expand Up @@ -54,20 +54,18 @@ License: Apache-2.0 AND (Apache-2.0 WITH LLVM-exception) AND BSD-3-Clause
%{_unitdir}/bootloader-update.service

%prep
%autosetup -n %{crate}-%{version} -p1 -Sgit
tar -xv -f %{SOURCE1}
mkdir -p .cargo
cat >.cargo/config << EOF
[source.crates-io]
replace-with = "vendored-sources"

[source.vendored-sources]
directory = "vendor"
EOF
%autosetup -n %{crate}-%{version} -p1 -Sgit -a1
# Default -v vendor config doesn't support non-crates.io deps (i.e. git)
cp .cargo/vendor-config.toml .
%cargo_prep -N
cat vendor-config.toml >> .cargo/config.toml
rm vendor-config.toml

%build
%cargo_build
%cargo_vendor_manifest
# https://pagure.io/fedora-rust/rust-packaging/issue/33
sed -i -e '/https:\/\//d' cargo-vendor.txt
%cargo_license_summary
%{cargo_license} > LICENSE.dependencies

Expand Down
3 changes: 2 additions & 1 deletion xtask/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ edition = "2021"
[dependencies]
anyhow = "1.0.68"
camino = "1.0"
chrono = { version = "0.4.23", default_features = false, features = ["std"] }
chrono = { version = "0.4.23", default-features = false, features = ["std"] }
fn-error-context = "0.2.0"
toml = "0.8"
tempfile = "3.3"
xshell = { version = "0.2" }
94 changes: 72 additions & 22 deletions xtask/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ use xshell::{cmd, Shell};

const NAME: &str = "bootupd";
const VENDORPATH: &str = "vendor.tar.zstd";
const TAR_REPRODUCIBLE_OPTS: &[&str] = &[
"--sort=name",
"--owner=0",
"--group=0",
"--numeric-owner",
"--pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime",
];

fn main() {
if let Err(e) = try_main() {
Expand Down Expand Up @@ -73,45 +80,88 @@ fn gitrev(sh: &Shell) -> Result<String> {
fn git_timestamp(sh: &Shell) -> Result<String> {
let ts = cmd!(sh, "git show -s --format=%ct").read()?;
let ts = ts.trim().parse::<i64>()?;
let ts = chrono::NaiveDateTime::from_timestamp_opt(ts, 0)
let ts = chrono::DateTime::from_timestamp(ts, 0)
.ok_or_else(|| anyhow::anyhow!("Failed to parse timestamp"))?;
Ok(ts.format("%Y%m%d%H%M").to_string())
}

struct Package {
version: String,
srcpath: Utf8PathBuf,
vendorpath: Utf8PathBuf,
}

/// Return the timestamp of the latest git commit in seconds since the Unix epoch.
fn git_source_date_epoch(dir: &Utf8Path) -> Result<u64> {
let o = Command::new("git")
.args(["log", "-1", "--pretty=%ct"])
.current_dir(dir)
.output()?;
if !o.status.success() {
anyhow::bail!("git exited with an error: {:?}", o);
}
let buf = String::from_utf8(o.stdout).context("Failed to parse git log output")?;
let r = buf.trim().parse()?;
Ok(r)
}


/// When using cargo-vendor-filterer --format=tar, the config generated has a bogus source
/// directory. This edits it to refer to vendor/ as a stable relative reference.
#[context("Editing vendor config")]
fn edit_vendor_config(config: &str) -> Result<String> {
let mut config: toml::Value = toml::from_str(config)?;
let config = config.as_table_mut().unwrap();
let source_table = config.get_mut("source").unwrap();
let source_table = source_table.as_table_mut().unwrap();
let vendored_sources = source_table.get_mut("vendored-sources").unwrap();
let vendored_sources = vendored_sources.as_table_mut().unwrap();
let previous =
vendored_sources.insert("directory".into(), toml::Value::String("vendor".into()));
assert!(previous.is_some());

Ok(config.to_string())
}

#[context("Packaging")]
fn impl_package(sh: &Shell) -> Result<Package> {
let source_date_epoch = git_source_date_epoch(".".into())?;
let v = gitrev(sh)?;
let timestamp = git_timestamp(sh)?;
// We always inject the timestamp first to ensure that newer is better.
let v = format!("{timestamp}.{v}");
println!("Using version {v}");

let namev = format!("{NAME}-{v}");
let target = get_target_dir()?;
let p = target.join(format!("{namev}.tar.zstd"));
let o = File::create(&p).context("Creating output file")?;
let p = Utf8Path::new("target").join(format!("{namev}.tar"));
let prefix = format!("{namev}/");
let st = Command::new("git")
.args([
"archive",
"--format=tar",
"--prefix",
prefix.as_str(),
"HEAD",
])
.stdout(Stdio::from(o))
.status()
.context("Executing git archive")?;
if !st.success() {
anyhow::bail!("Failed to run {st:?}");
cmd!(sh, "git archive --format=tar --prefix={prefix} -o {p} HEAD").run()?;
// Generate the vendor directory now, as we want to embed the generated config to use
// it in our source.
let vendorpath = Utf8Path::new("target").join(format!("{namev}-vendor.tar.zstd"));
let vendor_config = cmd!(
sh,
"cargo vendor-filterer --prefix=vendor --format=tar.zstd {vendorpath}"
)
.read()?;
let vendor_config = edit_vendor_config(&vendor_config)?;
// Append .cargo/vendor-config.toml (a made up filename) into the tar archive.
{
let tmpdir = tempfile::tempdir_in("target")?;
let tmpdir_path = tmpdir.path();
let path = tmpdir_path.join("vendor-config.toml");
std::fs::write(&path, vendor_config)?;
let source_date_epoch = format!("{source_date_epoch}");
cmd!(
sh,
"tar -r -C {tmpdir_path} {TAR_REPRODUCIBLE_OPTS...} --mtime=@{source_date_epoch} --transform=s,^,{prefix}.cargo/, -f {p} vendor-config.toml"
)
.run()?;
}
// Compress with zstd
let srcpath: Utf8PathBuf = format!("{p}.zstd").into();
cmd!(sh, "zstd --rm -f {p} -o {srcpath}").run()?;

Ok(Package {
version: v,
srcpath: p,
srcpath,
vendorpath,
})
}

Expand Down