From 682d831ce8dd71c650daa18dcc22b9bd60fa4b85 Mon Sep 17 00:00:00 2001 From: madomado Date: Sat, 30 Sep 2023 17:52:41 +0800 Subject: [PATCH 1/2] just some refactoring? --- README.md | 1 + src/config.rs | 47 ++++++++++++----------------- src/creator.rs | 80 ++++---------------------------------------------- 3 files changed, 25 insertions(+), 103 deletions(-) diff --git a/README.md b/README.md index c21f635..4a41df7 100644 --- a/README.md +++ b/README.md @@ -24,3 +24,4 @@ Katsu uses YAML configuration files to describe the image, with modular manifest - `limine` or `grub2` - `rpm` - `dnf` or `dnf5` +- `systemd-devel` diff --git a/src/config.rs b/src/config.rs index 8a810c8..bd2a0f0 100644 --- a/src/config.rs +++ b/src/config.rs @@ -36,34 +36,26 @@ impl Manifest { let mut path_can = path; path_can.pop(); - for import in manifest.import.clone() { - println!("Import: {:#?}", import); - // swap the import with the canonicalized path - let import_ord = manifest.import.iter().position(|x| *x == import).unwrap(); - // replace - let cn = path_can.join(import).canonicalize()?; - println!("Canonicalized import: {:#?}", cn); - manifest.import[import_ord] = cn.clone(); + for import in &mut manifest.import { + debug!("Import: {import:#?}"); + // swap canonicalized path + let cn = path_can.join(&import).canonicalize()?; + debug!("Canonicalized import: {cn:#?}"); + *import = cn; } // canonicalize all file paths in scripts, then modify their paths put in the manifest - for mut script in manifest.scripts.pre.clone() { - if script.file.is_some() { - script.file = Some(script.file.as_ref().unwrap().canonicalize()?); + for script in &mut manifest.scripts.pre { + if let Some(f) = script.file.as_mut() { + *f = f.canonicalize()?; } - // replace old path - let script_ord = manifest.scripts.pre.iter().position(|x| *x == script).unwrap(); - manifest.scripts.pre[script_ord] = script.clone(); } - for mut script in manifest.scripts.post.clone() { - if script.file.is_some() { - script.file = Some(script.file.as_ref().unwrap().canonicalize()?); + for script in &mut manifest.scripts.post { + if let Some(f) = script.file.as_mut() { + *f = f.canonicalize()?; } - // replace old path - let script_ord = manifest.scripts.post.iter().position(|x| *x == script).unwrap(); - manifest.scripts.post[script_ord] = script.clone(); } Ok(manifest) @@ -97,8 +89,6 @@ impl Manifest { } } - - #[derive(Deserialize, Debug, Clone, Serialize, Default)] pub struct ScriptsManifest { #[serde(default)] @@ -117,14 +107,13 @@ pub struct Script { impl Script { pub fn load(&self) -> Option { if self.inline.is_some() { - return self.inline.clone(); - } else if self.file.is_some() { - return std::fs::read_to_string( - self.file.as_ref().unwrap().canonicalize().unwrap_or_default(), - ) - .ok(); + self.inline.clone() + } else if let Some(f) = &self.file { + std::fs::read_to_string(f.canonicalize().unwrap_or_default()).ok() } else { - return None; + self.file + .as_ref() + .and_then(|f| std::fs::read_to_string(f.canonicalize().unwrap_or_default()).ok()) } } } diff --git a/src/creator.rs b/src/creator.rs index af3c588..5be131c 100644 --- a/src/creator.rs +++ b/src/creator.rs @@ -5,7 +5,6 @@ use std::{ path::{Path, PathBuf}, }; use tracing::{debug, error, info, instrument, trace, warn}; -use tracing_subscriber::field::debug; use crate::{ cfg::{Config, OutputFormat}, @@ -17,7 +16,6 @@ const DEFAULT_DNF: &str = "dnf5"; const DEFAULT_BOOTLOADER: &str = "limine"; // const UBOOT_DATA: &str = "/usr/share/uboot"; - pub trait ImageCreator { /// src, dest, required const EFI_FILES: &'static [(&'static str, &'static str, bool)]; @@ -41,10 +39,8 @@ pub trait ImageCreator { let cfg = self.get_cfg(); let root = cfg.instroot.canonicalize().expect("Cannot canonicalize instroot."); let root = root.to_str().unwrap(); - let out = format!("{}/etc/fstab", root); - cmd_lib::run_cmd!( - mkdir -p $root/etc; - )?; + let out = format!("{root}/etc/fstab"); + cmd_lib::run_cmd!(mkdir -p $root/etc)?; // list mounts in $root let mounts = cmd_lib::run_fun!(findmnt -n -o UUID,TARGET,FSTYPE,OPTIONS --real --raw --noheadings --notruncate --output-all --target $root)?; @@ -52,18 +48,8 @@ pub trait ImageCreator { let mut mounts = mounts .lines() .map(|x| { - let mut x = x.split_whitespace(); - let uuid = x.next().unwrap(); - let target = x.next().unwrap(); - let fstype = x.next().unwrap(); - let options = x.next().unwrap(); - format!( - "UUID={uuid}\t{target}\t{fstype}\t{options}\t0\t0", - uuid = uuid, - target = target, - fstype = fstype, - options = options - ) + let [uuid, target, fstype, options] = x.split_whitespace().collect::>()[..] else { panic!("Bad output from findmnt: {x}"); }; + format!("UUID={uuid}\t{target}\t{fstype}\t{options}\t0\t0") }) .collect::>() .join("\n"); @@ -274,16 +260,14 @@ pub trait ImageCreator { let kver = &Self::get_krnl_ver(root.to_str().unwrap())?; let kver = kver.trim_start_matches("kernel-"); let volid = &cfg.volid; - let cmdline = cfg.sys.kernel_params.as_ref().map(String::as_str).unwrap_or_default(); + let cmd = cfg.sys.kernel_params.as_ref().map(String::as_str).unwrap_or_default(); let mut f = std::fs::File::create(path) .map_err(|e| eyre!(e).wrap_err("Cannot create limine.cfg"))?; f.write_fmt(format_args!("TIMEOUT=5\n\n:{distro}\n\tPROTOCOL=linux\n\t"))?; f.write_fmt(format_args!("KERNEL_PATH=boot:///boot/vmlinuz-{kver}\n\t"))?; f.write_fmt(format_args!("MODULE_PATH=boot:///boot/initramfs-{kver}.img\n\t"))?; - f.write_fmt(format_args!( - "CMDLINE=root=live:LABEL={volid} rd.live.image selinux=0 {cmdline}" - ))?; // maybe enforcing=0 + f.write_fmt(format_args!("CMDLINE=root=live:LABEL={volid} rd.live.image selinux=0 {cmd}"))?; Ok(()) } @@ -660,7 +644,6 @@ impl From for KatsuCreator { } } impl ImageCreator for KatsuCreator { - // const ARCH: crate::util::Arch = crate::util::Arch::X86; const EFI_FILES: &'static [(&'static str, &'static str, bool)] = &[ ("/boot/efi/EFI/*/shim%arch%.efi", "/EFI/BOOT/BOOT%arch%.EFI", true), ("/boot/efi/EFI/*/gcd%arch%.efi", "/EFI/BOOT/grub%arch%.efi", true), @@ -675,57 +658,6 @@ impl ImageCreator for KatsuCreator { } } -// @madonuko: why? Why did you hardcode everything per architecture? I... My sanity hurts. -@korewaChino -// pub struct LiveImageCreatorX86 { -// cfg: Config, -// } - -// impl From for LiveImageCreatorX86 { -// fn from(cfg: Config) -> Self { -// Self { cfg } -// } -// } - -// impl ImageCreator for LiveImageCreatorX86 { -// // const ARCH: crate::util::Arch = crate::util::Arch::X86; -// const EFI_FILES: &'static [(&'static str, &'static str, bool)] = &[ -// ("/boot/efi/EFI/*/shim%arch%.efi", "/EFI/BOOT/BOOT%arch%.EFI", true), -// ("/boot/efi/EFI/*/gcd%arch%.efi", "/EFI/BOOT/grub%arch%.efi", true), -// ("/boot/efi/EFI/*/shimia32.efi", "/EFI/BOOT/BOOTIA32.EFI", false), -// ("/boot/efi/EFI/*/gcdia32.efi", "/EFI/BOOT/grubia32.efi", false), -// ("/usr/share/grub/unicode.pf2", "/EFI/BOOT/fonts/", true), -// ]; - -// #[inline] -// fn get_cfg(&self) -> &Config { -// &self.cfg -// } -// } -// pub struct LiveImageCreatorX86_64 { -// cfg: Config, -// } - -// impl From for LiveImageCreatorX86_64 { -// fn from(cfg: Config) -> Self { -// Self { cfg } -// } -// } - -// impl ImageCreator for LiveImageCreatorX86_64 { -// // const ARCH: crate::util::Arch = crate::util::Arch::X86_64; -// const EFI_FILES: &'static [(&'static str, &'static str, bool)] = &[ -// ("/boot/efi/EFI/*/shim%arch%.efi", "/EFI/BOOT/BOOT%arch%.EFI", true), -// ("/boot/efi/EFI/*/gcd%arch%.efi", "/EFI/BOOT/grub%arch%.efi", true), -// ("/boot/efi/EFI/*/shimia32.efi", "/EFI/BOOT/BOOTIA32.EFI", false), -// ("/boot/efi/EFI/*/gcdia32.efi", "/EFI/BOOT/grubia32.efi", false), -// ("/usr/share/grub/unicode.pf2", "/EFI/BOOT/fonts/", true), -// ]; - -// fn get_cfg(&self) -> &Config { -// &self.cfg -// } -// } - /// Prepare chroot by mounting /dev, /proc, /sys fn prepare_chroot(root: &str) -> Result<()> { cmd_lib::run_cmd! ( From 9a60962287d9cb4fb2490f2c9cbcd96d4e932e8a Mon Sep 17 00:00:00 2001 From: madomado Date: Sun, 1 Oct 2023 14:17:08 +0800 Subject: [PATCH 2/2] more refactoring --- src/builder.rs | 15 ++-- src/config.rs | 2 +- src/creator.rs | 192 +++++++++++++++++++++---------------------------- 3 files changed, 90 insertions(+), 119 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 01094ae..ae0cb8d 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -34,22 +34,19 @@ impl RootBuilder for DnfRootBuilder { let exclude = self.exclude.clone(); let releasever = &self.releasever; - if self.arch.is_some() { - options.push(format!("--forcearch={}", self.arch.as_ref().unwrap())); + if let Some(a) = &self.arch { + options.push(format!("--forcearch={a}")); } - // Get host architecture using uname + // Get host architecture using uname let host_arch = cmd_lib::run_fun!(uname -m;)?; let arch_string = self.arch.as_ref().unwrap_or(&host_arch); - if self.arch_packages.contains_key(arch_string) { - packages.append(&mut self.arch_packages.get(arch_string).unwrap().clone()); - } - - for package in exclude { - options.push(format!("--exclude={}", package)); + if let Some(pkg) = self.arch_packages.get(arch_string) { + packages.append(&mut pkg.clone()); } + options.append(&mut exclude.iter().map(|p| format!("--exclude={p}")).collect()); cmd_lib::run_cmd!( dnf -y --releasever=${releasever} --installroot=${chroot} $[packages] $[options]; diff --git a/src/config.rs b/src/config.rs index bd2a0f0..097b662 100644 --- a/src/config.rs +++ b/src/config.rs @@ -124,7 +124,7 @@ fn test_recurse() { let manifest = Manifest::load_all(PathBuf::from("tests/ng/recurse/manifest.yaml")).unwrap(); - println!("{:#?}", manifest); + println!("{manifest:#?}"); // let ass: Manifest = Manifest { import: vec!["recurse1.yaml", "recurse2.yaml"], distro: Some("RecursiveOS"), out_file: None, dnf: (), scripts: () } } diff --git a/src/creator.rs b/src/creator.rs index 5be131c..b78fc4c 100644 --- a/src/creator.rs +++ b/src/creator.rs @@ -1,9 +1,5 @@ use color_eyre::{eyre::eyre, Help, Result}; -use std::{ - fs, - io::Write, - path::{Path, PathBuf}, -}; +use std::{io::Write, path::Path}; use tracing::{debug, error, info, instrument, trace, warn}; use crate::{ @@ -430,139 +426,120 @@ pub trait ImageCreator { fn prep_disk(&self) -> Result<()> { let cfg = self.get_cfg(); - if let Some(layout) = &cfg.disk { - // Now let's create a disk file called {out}.raw - let out_file = format!("{}.raw", cfg.out); + let layout = cfg.disk.as_ref().ok_or_else(|| eyre!("No disk layout specified"))?; + // Now let's create a disk file called {out}.raw + let out_file = format!("{}.raw", cfg.out); - // Create the disk file + // Create the disk file - let disk_size = &layout.disk_size; - info!(out_file, "Creating disk file"); + let disk_size = &layout.disk_size; + info!(out_file, "Creating disk file"); - cmd_lib::run_cmd!( - truncate -s $disk_size $out_file; - )?; + cmd_lib::run_cmd!( + truncate -s $disk_size $out_file; + )?; - // Mount disk image to loop device, and return the loop device name + // Mount disk image to loop device, and return the loop device name - info!("Mounting disk image to loop device"); + info!("Mounting disk image to loop device"); + let loop_dev = cmd_lib::run_fun!(losetup -f;)?; + debug!("Found loop device: {loop_dev:?}"); - // The reason we run this command instead of just losetup -f is - // because rustfmt messes up the formatting of the command - let loop_dev = cmd_lib::run_fun!(bash -c "losetup -f")?; + cmd_lib::run_cmd!(losetup $loop_dev $out_file --show;)?; - debug!("Found loop device: {loop_dev:?}"); + info!("Partitioning disk"); + // Create partition table, GPT + cmd_lib::run_cmd!(parted -s $loop_dev mklabel gpt;)?; - cmd_lib::run_cmd!( - losetup $loop_dev $out_file --show; - )?; + // number to track partition number + let mut part_num = 1; + let mut efi_num: Option = None; + let boot_num: i32; + let root_num: i32; - // Partition disk - - info!("Partitioning disk"); - - // Create partition table, GPT + if layout.bootloader { + // create EFI partition with ESP flag for the first 250MiB + // label it as EFI cmd_lib::run_cmd!( - parted -s $loop_dev mklabel gpt; + parted -s $loop_dev mkpart primary fat32 1MiB 250MiB; + parted -s $loop_dev set $part_num esp on; + parted -s $loop_dev name $part_num EFI; )?; - // number to track partition number - - let mut part_num = 1; - let mut efi_num: Option = None; - let boot_num: i32; - let root_num: i32; - - if layout.bootloader { - // create EFI partition with ESP flag for the first 250MiB - // label it as EFI - - cmd_lib::run_cmd!( - parted -s $loop_dev mkpart primary fat32 1MiB 250MiB; - parted -s $loop_dev set $part_num esp on; - parted -s $loop_dev name $part_num EFI; - )?; + // debug lsblk - // debug lsblk + cmd_lib::run_cmd!( + lsblk; + partprobe $loop_dev; + ls -l /dev; + )?; - cmd_lib::run_cmd!( - lsblk; - partprobe $loop_dev; - ls -l /dev; - )?; + // format EFI partition - // format EFI partition + cmd_lib::run_cmd!(mkfs.fat -F32 ${loop_dev}p$part_num -n EFI;)?; + efi_num = Some(part_num); - cmd_lib::run_cmd!( - mkfs.fat -F32 ${loop_dev}p$part_num -n EFI 2>&1; - )?; - efi_num = Some(part_num); + // increment partition number + part_num += 1; + } - // increment partition number - part_num += 1; - } + // create boot partition for installing kernels with the next 1GiB + // label as BOOT + // ext4 + cmd_lib::run_cmd!( + parted -s $loop_dev mkpart primary ext4 250MiB 1.25GiB; + parted -s $loop_dev name $part_num BOOT; + )?; - // create boot partition for installing kernels with the next 1GiB - // label as BOOT - // ext4 - cmd_lib::run_cmd!( - parted -s $loop_dev mkpart primary ext4 250MiB 1.25GiB; - parted -s $loop_dev name $part_num BOOT; - )?; + cmd_lib::run_cmd!( + mkfs.ext4 -F ${loop_dev}p$part_num -L BOOT; + )?; - cmd_lib::run_cmd!( - mkfs.ext4 -F ${loop_dev}p$part_num -L BOOT; - )?; + boot_num = part_num; - boot_num = part_num; + part_num += 1; - part_num += 1; + // Create blank partition with the rest of the free space - // Create blank partition with the rest of the free space + let volid = &cfg.volid; + cmd_lib::run_cmd!( + parted -s $loop_dev mkpart primary ext4 1.25GiB 100%; + parted -s $loop_dev name $part_num $volid; + )?; - let volid = &cfg.volid; - cmd_lib::run_cmd!( - parted -s $loop_dev mkpart primary ext4 1.25GiB 100%; - parted -s $loop_dev name $part_num $volid; - )?; + root_num = part_num; - root_num = part_num; + // now format the partition - // now format the partition + let root_format = &layout.root_format; - let root_format = &layout.root_format; + cmd_lib::run_cmd!( + mkfs.${root_format} ${loop_dev}p$part_num -L $volid; + )?; - cmd_lib::run_cmd!( - mkfs.${root_format} ${loop_dev}p$part_num -L $volid; - )?; + // Now, mount them all - // Now, mount them all + info!("Mounting partitions"); - info!("Mounting partitions"); + let instroot = &cfg.instroot.to_str().unwrap_or_default(); - let instroot = &cfg.instroot.to_str().unwrap_or_default(); + cmd_lib::run_cmd!( + mkdir -p $instroot; + mount ${loop_dev}p$root_num $instroot; + mkdir -p $instroot/boot; + mount ${loop_dev}p$boot_num $instroot/boot; + )?; + if layout.bootloader { + let efi_num = efi_num.unwrap(); cmd_lib::run_cmd!( - mkdir -p $instroot; - mount ${loop_dev}p$root_num $instroot; - mkdir -p $instroot/boot; - mount ${loop_dev}p$boot_num $instroot/boot; + mkdir -p $instroot/boot/efi; + mount ${loop_dev}p$efi_num $instroot/boot/efi; )?; - - if layout.bootloader { - let efi_num = efi_num.unwrap(); - cmd_lib::run_cmd!( - mkdir -p $instroot/boot/efi; - mount ${loop_dev}p$efi_num $instroot/boot/efi; - )?; - } - - Ok(()) - } else { - // error out - return Err(eyre!("No disk layout specified")); } + + Ok(()) } #[instrument(skip(self))] @@ -610,9 +587,9 @@ pub trait ImageCreator { // } let mut extra_args = vec![]; - if cfg.arch.is_some() { + if let Some(arch) = &cfg.arch { extra_args.push("--forcearch"); - extra_args.push(cfg.arch.as_ref().unwrap()); + extra_args.push(arch); } prepare_chroot(root).unwrap_or_else(|e| { error!(?e, "Failed to prepare chroot"); @@ -624,10 +601,7 @@ pub trait ImageCreator { ) .unwrap_or_else(|e| { error!(?e, "Failed to install packages"); - unmount_chroot(root).unwrap_or_else(|e| { - error!(?e, "Failed to unmount chroot"); - std::process::exit(1); - }); + unmount_chroot(root).unwrap_or_else(|e| error!(?e, "Failed to unmount chroot")); std::process::exit(1); }); unmount_chroot(root)?;