Skip to content

Commit

Permalink
Rework build infra, add manpages into tarball
Browse files Browse the repository at this point in the history
- Inject pre-generated manpages into the source tarball we make
- Ensure we use the git tag for version if there is one

Immediate motivation is making sure man pages end up in e.g.
RPM builds.

Signed-off-by: Colin Walters <[email protected]>
  • Loading branch information
cgwalters committed Oct 12, 2023
1 parent 5f8e9dc commit 7d62127
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 13 deletions.
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ all-test:
cargo build --release --all-features

install:
install -D -t $(DESTDIR)$(prefix)/bin target/release/bootc
install -D -t $(DESTDIR)$(prefix)/lib/bootc/install lib/src/install/*.toml
install -D -m 0755 -t $(DESTDIR)$(prefix)/bin target/release/bootc
install -D -m 0644 -t $(DESTDIR)$(prefix)/lib/bootc/install lib/src/install/*.toml
if test -d man; then install -D -m 0644 -t $(DESTDIR)$(prefix)/share/man/man8 man/*.8; fi

bin-archive: all
$(MAKE) install DESTDIR=tmp-install && tar --zstd -C tmp-install -cf target/bootc.tar.zst . && rm tmp-install -rf
Expand Down
5 changes: 3 additions & 2 deletions contrib/packaging/bootc.spec
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ Summary: Boot containers

License: ASL 2.0
URL: https://github.com/containers/bootc
Source0: https://github.com/containers/bootc/releases/download/v%{version}/bootc-%{version}.tar.zstd
Source1: https://github.com/containers/bootc/releases/download/v%{version}/bootc-%{version}-vendor.tar.zstd
Source0: https://github.com/containers/bootc/releases/download/v%{version}/bootc-%{version}.tar.zst
Source1: https://github.com/containers/bootc/releases/download/v%{version}/bootc-%{version}-vendor.tar.zst

BuildRequires: make
BuildRequires: openssl-devel
Expand All @@ -29,6 +29,7 @@ BuildRequires: systemd-devel
%doc README.md
%{_bindir}/bootc
%{_prefix}/lib/bootc
%{_mandir}/man8/bootc*

%prep
%autosetup -p1 -Sgit
Expand Down
11 changes: 10 additions & 1 deletion lib/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,16 @@ pub(crate) enum TestingOpts {
},
}

/// Deploy and upgrade via bootable container images.
/// Deploy and transactionally in-place with bootable container images.
///
/// The `bootc` project currently uses ostree-containers as a backend
/// to support a model of bootable container images. Once installed,
/// whether directly via `bootc install` (executed as part of a container)
/// or via another mechanism such as an OS installer tool, further
/// updates can be pulled via e.g. `bootc upgrade`.
///
/// Changes in `/etc` and `/var` persist.
///
#[derive(Debug, Parser)]
#[clap(name = "bootc")]
#[clap(rename_all = "kebab-case")]
Expand Down
77 changes: 69 additions & 8 deletions xtask/src/xtask.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ fn main() {
#[allow(clippy::type_complexity)]
const TASKS: &[(&str, fn(&Shell) -> Result<()>)] = &[
("vendor", vendor),
("manpages", manpages),
("package", package),
("package-srpm", package_srpm),
("custom-lints", custom_lints),
Expand Down Expand Up @@ -57,15 +58,31 @@ fn gitrev_to_version(v: &str) -> String {

#[context("Finding gitrev")]
fn gitrev(sh: &Shell) -> Result<String> {
if let Ok(rev) = cmd!(sh, "git describe --tags").ignore_stderr().read() {
if let Ok(rev) = cmd!(sh, "git describe --tags --exact-match")
.ignore_stderr()
.read()
{
Ok(gitrev_to_version(&rev))
} else {
let mut desc = cmd!(sh, "git describe --tags --always").read()?;
desc.insert_str(0, "0.");
Ok(desc)
let timestamp = git_timestamp(sh)?;
// We always inject the timestamp first to ensure that newer is better.
Ok(format!("{timestamp}.{desc}"))
}
}

#[context("Manpages")]
fn manpages(sh: &Shell) -> Result<()> {
sh.create_dir("target/man")?;
cmd!(
sh,
"cargo run --features=docgen -- man --directory target/man"
)
.run()?;
Ok(())
}

/// Return a string formatted version of the git commit timestamp, up to the minute
/// but not second because, well, we're not going to build more than once a second.
#[context("Finding git timestamp")]
Expand All @@ -82,14 +99,28 @@ struct Package {
srcpath: 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)
}

#[context("Packaging")]
fn impl_package(sh: &Shell) -> Result<Package> {
let source_date_epoch = git_source_date_epoch(".".into())?;
manpages(sh)?;
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}");

let namev = format!("{NAME}-{v}");
let p = Utf8Path::new("target").join(format!("{namev}.tar.zstd"));
let p = Utf8Path::new("target").join(format!("{namev}.tar"));
let o = File::create(&p)?;
let prefix = format!("{namev}/");
let st = Command::new("git")
Expand All @@ -105,9 +136,29 @@ fn impl_package(sh: &Shell) -> Result<Package> {
if !st.success() {
anyhow::bail!("Failed to run {st:?}");
}
let st = Command::new("tar")
.args([
"-r",
"-C",
"target",
"--sort=name",
"--owner=0",
"--group=0",
"--numeric-owner",
"--pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime",
])
.arg(format!("--transform=s,^,{prefix},"))
.arg(format!("--mtime=@{source_date_epoch}"))
.args(["-f", p.as_str(), "man"])
.status()
.context("Failed to execute tar")?;
if !st.success() {
anyhow::bail!("Failed to run {st:?}");
}
cmd!(sh, "zstd -f {p}").run()?;
Ok(Package {
version: v,
srcpath: p,
srcpath: format!("{p}.zst").into(),
})
}

Expand All @@ -118,6 +169,16 @@ fn package(sh: &Shell) -> Result<()> {
}

fn impl_srpm(sh: &Shell) -> Result<Utf8PathBuf> {
{
let _g = sh.push_dir("target");
for name in sh.read_dir(".")? {
if let Some(name) = name.to_str() {
if name.ends_with(".src.rpm") {
sh.remove_path(name)?;
}
}
}
}
let pkg = impl_package(sh)?;
vendor(sh)?;
let td = tempfile::tempdir_in("target").context("Allocating tmpdir")?;
Expand All @@ -126,7 +187,7 @@ fn impl_srpm(sh: &Shell) -> Result<Utf8PathBuf> {
let srcpath = td.join(pkg.srcpath.file_name().unwrap());
std::fs::rename(pkg.srcpath, srcpath)?;
let v = pkg.version;
let vendorpath = td.join(format!("{NAME}-{v}-vendor.tar.zstd"));
let vendorpath = td.join(format!("{NAME}-{v}-vendor.tar.zst"));
std::fs::rename(VENDORPATH, vendorpath)?;
{
let specin = File::open(format!("contrib/packaging/{NAME}.spec"))
Expand Down

0 comments on commit 7d62127

Please sign in to comment.