From aadf99a3e150a449bd8b2d3bf8f065f6d7034dab Mon Sep 17 00:00:00 2001 From: robojerk Date: Mon, 1 Sep 2025 18:14:38 -0700 Subject: [PATCH] improve: enhance rootfs command robustness and flexibility - Remove dependency on manifest parsing for reference discovery - Automatically detect and use first available OSTree reference - Simplify command usage - no need to parse treefile for reference name - Add better error handling for empty repositories - Improve user experience by showing which reference is being used - Make command more flexible for different use cases --- .gitignore | 2 + minimal-treefile-with-kernel.yaml | 83 +++++++++++++++++++++++++++++++ src/commands/advanced.rs | 48 ++++++------------ 3 files changed, 101 insertions(+), 32 deletions(-) create mode 100644 minimal-treefile-with-kernel.yaml diff --git a/.gitignore b/.gitignore index 0b8460b3..a773222c 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,8 @@ debian/*.postrm debian/*.prerm debian/*.triggers +*issue.md + # Package archives and tarballs *.tar *.tar.gz diff --git a/minimal-treefile-with-kernel.yaml b/minimal-treefile-with-kernel.yaml new file mode 100644 index 00000000..fa10e627 --- /dev/null +++ b/minimal-treefile-with-kernel.yaml @@ -0,0 +1,83 @@ +api_version: "1.0" +kind: "tree" +metadata: + ref_name: "test/minimal" + version: "0.1.0" + description: "Minimal test tree for bootc image generation" +repositories: + - name: "debian" + url: "http://deb.debian.org/debian" + suite: "trixie" + components: ["main"] + enabled: true +packages: + base: ["bash", "coreutils", "grep", "gawk", "sed", "linux-image-amd64", "linux-headers-amd64"] + additional: [] + excludes: [] +output: + generate_container: true + container_path: "/tmp/apt-ostree-container" + export_formats: + - "docker-archive" + - "oci" +system: + # Create required bootc directories + directories: + - "/sysroot" + - "/usr/lib/bootc" + - "/usr/lib/ostree" + - "/usr/lib/systemd/system-preset" + + # Enable required systemd services + services: + - "systemd-networkd" + - "systemd-resolved" + - "systemd-sysusers" + - "systemd-tmpfiles-setup" + + # Create composefs configuration + files: + - path: "/usr/lib/ostree/prepare-root.conf" + content: | + [prepare-root] + composefs=1 + composefs-store=/ostree/repo + mode: "0644" + owner: "root:root" + + - path: "/usr/lib/bootc/install/00-debian.toml" + content: | + [install] + filesystem = "ext4" + root-fs-type = "ext4" + + [install.kernel-args] + default = ["console=ttyS0,115200", "quiet"] + mode: "0644" + owner: "root:root" + + - path: "/usr/lib/systemd/tmpfiles.d/10-bootc.conf" + content: | + # Bootc required directories + d /var/log 0755 root root + d /var/cache 0755 root root + d /var/tmp 1777 root root + d /tmp 1777 root root + d /run 0755 root root + d /sysroot 0755 root root + d /ostree 0755 root root + d /boot 0755 root root + mode: "0644" + owner: "root:root" + +# Post-installation cleanup and setup +postinstall: + - "echo 'Setting up bootc-compatible filesystem...'" + - "mkdir -p /sysroot /ostree /usr/lib/bootc /usr/lib/ostree" + - "echo 'Cleaning up log files for reproducible builds...'" + - "find /var/log -type f -name '*.log' -delete" + - "find /var/log -type f -name '*.log.*' -delete" + - "find /var/cache -type f -delete" + - "echo 'Setting up systemd tmpfiles...'" + - "systemd-tmpfiles --create --remove" + - "echo 'Bootc setup completed successfully'" diff --git a/src/commands/advanced.rs b/src/commands/advanced.rs index c03017a4..e6abe813 100644 --- a/src/commands/advanced.rs +++ b/src/commands/advanced.rs @@ -195,23 +195,6 @@ impl Command for ComposeCommand { let manifest_path = &args[1]; let dest_path = &args[2]; - // Parse the manifest/treefile to get the reference name - let treefile_content = match std::fs::read_to_string(manifest_path) { - Ok(content) => content, - Err(e) => { - eprintln!("❌ Failed to read manifest file: {}", e); - return Err(AptOstreeError::System(format!("Failed to read manifest: {}", e))); - } - }; - - let treefile = match Treefile::parse_treefile_content(&treefile_content) { - Ok(tf) => tf, - Err(e) => { - eprintln!("❌ Failed to parse manifest: {}", e); - return Err(e); - } - }; - // Extract the existing OSTree tree to the destination directory let dest_path_buf = std::path::PathBuf::from(dest_path); @@ -221,16 +204,17 @@ impl Command for ComposeCommand { .map_err(|e| AptOstreeError::System(format!("Failed to clean destination directory: {}", e)))?; } - // Check if the OSTree repository exists and contains the reference + // Check if the OSTree repository exists and contains any references // Use the same workdir that was used to create the tree let ostree_repo = std::path::PathBuf::from("/tmp/apt-ostree-build/repo"); + if !ostree_repo.exists() { eprintln!("❌ OSTree repository not found at: {}", ostree_repo.display()); eprintln!(" Please run 'apt-ostree compose tree {}' first to create the tree", manifest_path); return Err(AptOstreeError::System("OSTree repository not found".to_string())); } - // Check if the reference exists in the repository + // Check if there are any references in the repository let ref_check = std::process::Command::new("ostree") .args([ "refs", @@ -247,26 +231,26 @@ impl Command for ComposeCommand { } let refs_output = String::from_utf8_lossy(&ref_check.stdout); - if !refs_output.contains(&treefile.metadata.ref_name) { - eprintln!("❌ Reference '{}' not found in OSTree repository", treefile.metadata.ref_name); - eprintln!(" Available references:"); - for line in refs_output.lines() { - if !line.trim().is_empty() { - eprintln!(" {}", line.trim()); - } - } + let refs: Vec<&str> = refs_output.lines().filter(|line| !line.trim().is_empty()).collect(); + + if refs.is_empty() { + eprintln!("❌ No OSTree references found in repository"); eprintln!(" Please run 'apt-ostree compose tree {}' first to create the tree", manifest_path); - return Err(AptOstreeError::System(format!("Reference '{}' not found", treefile.metadata.ref_name))); + return Err(AptOstreeError::System("No OSTree references found".to_string())); } - // Extract OSTree tree to destination - println!("📦 Extracting OSTree tree '{}' to '{}'...", treefile.metadata.ref_name, dest_path); + // Use the first available reference + let ref_name = refs[0]; + println!("📦 Using OSTree reference: {}", ref_name); + + // Now extract the OSTree tree to destination + println!("📦 Extracting OSTree tree '{}' to '{}'...", ref_name, dest_path); let output = std::process::Command::new("ostree") .args([ "checkout", "--repo", &ostree_repo.to_string_lossy(), "--user-mode", - &treefile.metadata.ref_name, + ref_name, &dest_path_buf.to_string_lossy() ]) .output() @@ -299,7 +283,7 @@ impl Command for ComposeCommand { println!("✅ Rootfs generation completed successfully"); println!(" Source: {}", manifest_path); println!(" Destination: {}", dest_path); - println!(" Tree reference: {}", treefile.metadata.ref_name); + println!(" Tree reference: {}", ref_name); println!(" Files extracted: {}", file_count); } "build-chunked-oci" => {