Skip to content

Commit

Permalink
wip: Add experimental compose tree-to-rootfs
Browse files Browse the repository at this point in the history
The loss of the buildah feature forces us to have a flow like this.
  • Loading branch information
cgwalters committed Feb 3, 2025
1 parent ef89de2 commit ee8e53e
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 2 deletions.
5 changes: 5 additions & 0 deletions rust/src/cli_experimental.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,17 @@ enum ComposeCmd {
#[clap(flatten)]
opts: crate::compose::BuildChunkedOCI,
},
TreeToRootfs {
#[clap(flatten)]
opts: crate::compose::TreeToRootfsOpts,
},
}

impl ComposeCmd {
fn run(self) -> Result<()> {
match self {
ComposeCmd::BuildChunkedOCI { opts } => opts.run(),
ComposeCmd::TreeToRootfs { opts } => opts.run(),
}
}
}
Expand Down
79 changes: 77 additions & 2 deletions rust/src/compose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use std::fs::File;
use std::io::{BufWriter, Write};
use std::os::fd::{AsFd, AsRawFd};
use std::process::Command;
use std::process::{Command, Stdio};

use anyhow::{anyhow, Context, Result};
use camino::{Utf8Path, Utf8PathBuf};
Expand All @@ -23,6 +23,7 @@ use ostree_ext::{oci_spec, ostree};

use crate::cmdutils::CommandRunExt;
use crate::cxxrsutil::{CxxResult, FFIGObjectWrapper};
use crate::isolation::self_command;

const SYSROOT: &str = "sysroot";
const USR: &str = "usr";
Expand Down Expand Up @@ -180,6 +181,22 @@ pub(crate) struct BuildChunkedOCI {
output: Utf8PathBuf,
}

/// Generate a "chunked" OCI archive from an input rootfs.
#[derive(Debug, Parser)]
pub(crate) struct TreeToRootfsOpts {
/// Path to the input manifest
manifest: Utf8PathBuf,

#[clap(long)]
#[clap(value_parser)]
/// Directory to use for caching downloaded packages and other data
cachedir: Option<Utf8PathBuf>,

/// Path to the target root filesystem tree.
#[clap(long, required = true)]
dest: Utf8PathBuf,
}

impl BuildChunkedOCI {
pub(crate) fn run(self) -> Result<()> {
anyhow::ensure!(self.rootfs.as_path() != "/");
Expand Down Expand Up @@ -229,6 +246,65 @@ impl BuildChunkedOCI {
}
}

impl TreeToRootfsOpts {
pub(crate) fn run(self) -> Result<()> {
let manifest = self.manifest.as_path();

if self.dest.try_exists()? {
anyhow::bail!("Refusing to operate on extant target {}", self.dest);
}

let td = tempfile::tempdir_in("/var/tmp")?;
let td_path: Utf8PathBuf = td.path().to_owned().try_into()?;
let repo_path = td_path.join("repo");
let repo = ostree::Repo::create_at(
libc::AT_FDCWD,
repo_path.as_str(),
ostree::RepoMode::BareUser,
None,
gio::Cancellable::NONE,
)?;
let commitid_path = td_path.join("commitid.txt");
self_command()
.args([
"compose",
"tree",
"--unified-core",
"--repo",
repo_path.as_str(),
"--write-commitid-to",
commitid_path.as_str(),
])
.args(self.cachedir.map(|v| format!("--cachedir={v}")))
.arg(manifest.as_str())
.run()?;
let commit = std::fs::read_to_string(commitid_path)?;
let commit = commit.trim();

std::fs::create_dir(self.dest)?;

let (piper, pipew) = rustix::pipe::pipe()?;
let piper = File::from(piper);
let pipew = File::from(pipew);

std::thread::scope(move |scope| {
let mktar =
scope.spawn(move || ostree_ext::tar::export_commit(&repo, &commit, pipew, None));
let unpacker = scope.spawn(move || {
Command::new("tar")
.args(["-x", "-f", "-"])
.stdin(Stdio::from(piper))
.run()
});
mktar.join().unwrap()?;
unpacker.join().unwrap()?;
anyhow::Ok(())
})?;

todo!()
}
}

fn label_to_xattrs(label: Option<&str>) -> Option<glib::Variant> {
let xattrs = label.map(|label| {
let mut label: Vec<_> = label.to_owned().into();
Expand Down Expand Up @@ -419,7 +495,6 @@ async fn fetch_previous_metadata(
}

pub(crate) fn compose_image(args: Vec<String>) -> CxxResult<()> {
use crate::isolation::self_command;
let cancellable = gio::Cancellable::NONE;

let opt = Opt::parse_from(args.iter().skip(1));
Expand Down

0 comments on commit ee8e53e

Please sign in to comment.