mirror of
https://github.com/marcoallegretti/WEFT_OS.git
synced 2026-03-27 09:23:09 +00:00
feat(pack): build-image and build-verity subcommands
build-image <dir> [--out <img>]: creates an EROFS image by invoking mkfs.erofs. Output filename defaults to <app_id>.app.img. Fails if the output file already exists or mkfs.erofs is unavailable. build-verity <img> [--out <hash>]: creates a dm-verity hash tree by invoking veritysetup format. Writes the hash device to <stem>.hash (or --out path). Extracts the root hash from veritysetup output and writes it to <img>.roothash. Fails if veritysetup is unavailable. Both subcommands shell out to external tools (erofs-utils and cryptsetup-bin respectively) and return an error with an installation hint if the binary is not found.
This commit is contained in:
parent
12fa53a585
commit
add4d92945
1 changed files with 73 additions and 0 deletions
|
|
@ -55,6 +55,22 @@ fn main() -> anyhow::Result<()> {
|
||||||
Some("list") => {
|
Some("list") => {
|
||||||
list_installed();
|
list_installed();
|
||||||
}
|
}
|
||||||
|
Some("build-image") => {
|
||||||
|
let dir = args.get(2).context("usage: weft-pack build-image <dir>")?;
|
||||||
|
let out = args
|
||||||
|
.windows(2)
|
||||||
|
.find(|w| w[0] == "--out")
|
||||||
|
.map(|w| w[1].as_str());
|
||||||
|
build_image(Path::new(dir), out.map(Path::new))?;
|
||||||
|
}
|
||||||
|
Some("build-verity") => {
|
||||||
|
let img = args.get(2).context("usage: weft-pack build-verity <img>")?;
|
||||||
|
let out = args
|
||||||
|
.windows(2)
|
||||||
|
.find(|w| w[0] == "--out")
|
||||||
|
.map(|w| w[1].as_str());
|
||||||
|
build_verity(Path::new(img), out.map(Path::new))?;
|
||||||
|
}
|
||||||
Some("bundle") => {
|
Some("bundle") => {
|
||||||
let dir = args.get(2).context("usage: weft-pack bundle <dir>")?;
|
let dir = args.get(2).context("usage: weft-pack bundle <dir>")?;
|
||||||
let out = args
|
let out = args
|
||||||
|
|
@ -111,6 +127,8 @@ fn main() -> anyhow::Result<()> {
|
||||||
eprintln!(" weft-pack install <dir> install package to app store");
|
eprintln!(" weft-pack install <dir> install package to app store");
|
||||||
eprintln!(" weft-pack uninstall <app_id> remove installed package");
|
eprintln!(" weft-pack uninstall <app_id> remove installed package");
|
||||||
eprintln!(" weft-pack list list installed packages");
|
eprintln!(" weft-pack list list installed packages");
|
||||||
|
eprintln!(" weft-pack build-image <dir> [--out <img>] create EROFS image with mkfs.erofs");
|
||||||
|
eprintln!(" weft-pack build-verity <img> [--out <hash>] add dm-verity hash tree");
|
||||||
eprintln!(" weft-pack bundle <dir> [--out <dir>] create .app.tar.zst archive");
|
eprintln!(" weft-pack bundle <dir> [--out <dir>] create .app.tar.zst archive");
|
||||||
eprintln!(" weft-pack unbundle <archive> [--out <dir>] extract .app.tar.zst");
|
eprintln!(" weft-pack unbundle <archive> [--out <dir>] extract .app.tar.zst");
|
||||||
eprintln!(" weft-pack generate-key [<outdir>] generate Ed25519 keypair");
|
eprintln!(" weft-pack generate-key [<outdir>] generate Ed25519 keypair");
|
||||||
|
|
@ -357,6 +375,61 @@ fn copy_dir(src: &Path, dst: &Path) -> anyhow::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_image(dir: &Path, out_path: Option<&Path>) -> anyhow::Result<()> {
|
||||||
|
let manifest = load_manifest(dir)?;
|
||||||
|
let app_id = &manifest.package.id;
|
||||||
|
let default_name = format!("{app_id}.app.img");
|
||||||
|
let output = match out_path {
|
||||||
|
Some(p) => p.to_path_buf(),
|
||||||
|
None => PathBuf::from(&default_name),
|
||||||
|
};
|
||||||
|
if output.exists() {
|
||||||
|
anyhow::bail!("{} already exists", output.display());
|
||||||
|
}
|
||||||
|
let status = std::process::Command::new("mkfs.erofs")
|
||||||
|
.arg(&output)
|
||||||
|
.arg(dir)
|
||||||
|
.status()
|
||||||
|
.context("spawn mkfs.erofs; ensure erofs-utils is installed")?;
|
||||||
|
if !status.success() {
|
||||||
|
anyhow::bail!("mkfs.erofs failed with status {status}");
|
||||||
|
}
|
||||||
|
println!("image: {}", output.display());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_verity(img: &Path, hash_out: Option<&Path>) -> anyhow::Result<()> {
|
||||||
|
let stem = img.file_stem().context("no file stem")?.to_string_lossy();
|
||||||
|
let default_hash = img.with_file_name(format!("{stem}.hash"));
|
||||||
|
let hash_path = hash_out.map(|p| p.to_path_buf()).unwrap_or(default_hash);
|
||||||
|
if hash_path.exists() {
|
||||||
|
anyhow::bail!("{} already exists", hash_path.display());
|
||||||
|
}
|
||||||
|
let output = std::process::Command::new("veritysetup")
|
||||||
|
.args(["format", &img.to_string_lossy(), &hash_path.to_string_lossy()])
|
||||||
|
.output()
|
||||||
|
.context("spawn veritysetup; ensure cryptsetup-bin is installed")?;
|
||||||
|
if !output.status.success() {
|
||||||
|
anyhow::bail!(
|
||||||
|
"veritysetup failed: {}",
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
let root_hash = stdout
|
||||||
|
.lines()
|
||||||
|
.find(|l| l.starts_with("Root hash:"))
|
||||||
|
.context("root hash not found in veritysetup output")?;
|
||||||
|
let hash_value = root_hash.trim_start_matches("Root hash:").trim();
|
||||||
|
let roothash_path = img.with_extension("roothash");
|
||||||
|
std::fs::write(&roothash_path, hash_value)
|
||||||
|
.with_context(|| format!("write {}", roothash_path.display()))?;
|
||||||
|
println!("hash image: {}", hash_path.display());
|
||||||
|
println!("root hash: {hash_value}");
|
||||||
|
println!("roothash: {}", roothash_path.display());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn bundle_package(dir: &Path, out_dir: Option<&Path>) -> anyhow::Result<()> {
|
fn bundle_package(dir: &Path, out_dir: Option<&Path>) -> anyhow::Result<()> {
|
||||||
let manifest = load_manifest(dir)?;
|
let manifest = load_manifest(dir)?;
|
||||||
let app_id = &manifest.package.id;
|
let app_id = &manifest.package.id;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue