Merge commit 'f819e9a9c5f1041770726a0a7595a01fe417711c'
This commit is contained in:
12
src/args.rs
12
src/args.rs
@@ -38,6 +38,12 @@ pub struct CreateCommand {
|
||||
#[structopt(parse(from_os_str))]
|
||||
pub path: Option<PathBuf>,
|
||||
|
||||
/// Path to a pacman.conf file which will be used to pacstrap packages into the image.
|
||||
///
|
||||
/// This pacman.conf will also be copied into the resulting Arch Linux image.
|
||||
#[structopt(short = "c", long = "pacman-conf", value_name = "pacman_conf")]
|
||||
pub pacman_conf: Option<PathBuf>,
|
||||
|
||||
/// Additional packages to install
|
||||
#[structopt(short = "p", long = "extra-packages", value_name = "package")]
|
||||
pub extra_packages: Vec<String>,
|
||||
@@ -46,6 +52,10 @@ pub struct CreateCommand {
|
||||
#[structopt(long = "aur-packages", value_name = "aurpackage")]
|
||||
pub aur_packages: Vec<String>,
|
||||
|
||||
/// Boot partition size in megabytes
|
||||
#[structopt(long = "boot-size")]
|
||||
pub boot_size: Option<u32>,
|
||||
|
||||
/// Enter interactive chroot before unmounting the drive
|
||||
#[structopt(short = "i", long = "interactive")]
|
||||
pub interactive: bool,
|
||||
@@ -78,7 +88,7 @@ pub struct CreateCommand {
|
||||
#[structopt(long = "allow-non-removable")]
|
||||
pub allow_non_removable: bool,
|
||||
|
||||
#[structopt(long = "aur-helper", possible_values=&["yay"], default_value="yay")]
|
||||
#[structopt(long = "aur-helper", possible_values=&["paru", "yay"], default_value="yay")]
|
||||
pub aur_helper: AurHelper,
|
||||
}
|
||||
|
||||
|
||||
24
src/aur.rs
24
src/aur.rs
@@ -3,6 +3,7 @@ use std::str::FromStr;
|
||||
|
||||
pub struct AurHelper {
|
||||
pub name: String,
|
||||
pub package_name: String,
|
||||
pub install_command: Vec<String>,
|
||||
}
|
||||
|
||||
@@ -11,8 +12,28 @@ impl FromStr for AurHelper {
|
||||
|
||||
fn from_str(s: &str) -> anyhow::Result<Self> {
|
||||
match s {
|
||||
"yay" => Ok(AurHelper {
|
||||
"paru" => Ok(Self {
|
||||
name: String::from("paru"),
|
||||
package_name: String::from("paru-bin"),
|
||||
install_command: vec![
|
||||
String::from("paru"),
|
||||
String::from("-S"),
|
||||
String::from("--skipreview"),
|
||||
String::from("--noupgrademenu"),
|
||||
String::from("--useask"),
|
||||
String::from("--removemake"),
|
||||
String::from("--norebuild"),
|
||||
String::from("--nocleanafter"),
|
||||
String::from("--noredownload"),
|
||||
String::from("--mflags"),
|
||||
String::from(""),
|
||||
String::from("--noconfirm"),
|
||||
String::from("--batchinstall"),
|
||||
],
|
||||
}),
|
||||
"yay" => Ok(Self {
|
||||
name: String::from("yay"),
|
||||
package_name: String::from("yay-bin"),
|
||||
install_command: vec![
|
||||
String::from("yay"),
|
||||
String::from("-S"),
|
||||
@@ -23,7 +44,6 @@ impl FromStr for AurHelper {
|
||||
String::from("--useask"),
|
||||
String::from("--removemake"),
|
||||
String::from("--norebuild"),
|
||||
String::from("--noconfirm"),
|
||||
String::from("--answeredit"),
|
||||
String::from("None"),
|
||||
String::from("--answerclean"),
|
||||
|
||||
208
src/main.rs
208
src/main.rs
@@ -162,12 +162,14 @@ fn create(command: args::CreateCommand) -> anyhow::Result<()> {
|
||||
info!("Partitioning the block device");
|
||||
debug!("{:?}", disk_path);
|
||||
|
||||
let boot_size = command.boot_size.unwrap_or(300);
|
||||
|
||||
sgdisk
|
||||
.execute()
|
||||
.args(&[
|
||||
"-Z",
|
||||
"-o",
|
||||
"--new=1::+250M",
|
||||
&format!("--new=1::+{}M", boot_size),
|
||||
"--new=2::+1M",
|
||||
"--largest-new=3",
|
||||
"--typecode=1:EF00",
|
||||
@@ -186,7 +188,7 @@ fn create(command: args::CreateCommand) -> anyhow::Result<()> {
|
||||
let root_partition_base = storage_device.get_partition(constants::ROOT_PARTITION_INDEX)?;
|
||||
let encrypted_root = if let Some(cryptsetup) = &cryptsetup {
|
||||
info!("Encrypting the root filesystem");
|
||||
EncryptedDevice::prepare(&cryptsetup, &root_partition_base)?;
|
||||
EncryptedDevice::prepare(cryptsetup, &root_partition_base)?;
|
||||
Some(EncryptedDevice::open(
|
||||
cryptsetup,
|
||||
&root_partition_base,
|
||||
@@ -225,13 +227,24 @@ fn create(command: args::CreateCommand) -> anyhow::Result<()> {
|
||||
|
||||
packages.extend(presets.packages);
|
||||
|
||||
if !presets.aur_packages.is_empty() {
|
||||
packages.extend(constants::AUR_DEPENDENCIES.iter().map(|s| String::from(*s)));
|
||||
}
|
||||
let aur_pacakges = {
|
||||
let mut p = vec![String::from("shim-signed")];
|
||||
p.extend(presets.aur_packages);
|
||||
p.extend(command.aur_packages);
|
||||
p
|
||||
};
|
||||
|
||||
packages.extend(constants::AUR_DEPENDENCIES.iter().map(|s| String::from(*s)));
|
||||
|
||||
let pacman_conf_path = command
|
||||
.pacman_conf
|
||||
.unwrap_or_else(|| "/etc/pacman.conf".into());
|
||||
|
||||
info!("Bootstrapping system");
|
||||
pacstrap
|
||||
.execute()
|
||||
.arg("-C")
|
||||
.arg(&pacman_conf_path)
|
||||
.arg("-c")
|
||||
.arg(mount_point.path())
|
||||
.args(packages)
|
||||
@@ -239,6 +252,10 @@ fn create(command: args::CreateCommand) -> anyhow::Result<()> {
|
||||
.run()
|
||||
.context("Pacstrap error")?;
|
||||
|
||||
// Copy pacman.conf to the image.
|
||||
fs::copy(pacman_conf_path, mount_point.path().join("etc/pacman.conf"))
|
||||
.context("Failed copying pacman.conf")?;
|
||||
|
||||
let fstab = fix_fstab(
|
||||
&genfstab
|
||||
.execute()
|
||||
@@ -257,84 +274,85 @@ fn create(command: args::CreateCommand) -> anyhow::Result<()> {
|
||||
.run()
|
||||
.context("Failed to delete the root password")?;
|
||||
|
||||
if !presets.aur_packages.is_empty() {
|
||||
arch_chroot
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.args(&["useradd", "-m", "aur"])
|
||||
.run()
|
||||
.context("Failed to create temporary user to install AUR packages")?;
|
||||
info!("Setting locale");
|
||||
fs::OpenOptions::new()
|
||||
.append(true)
|
||||
.write(true)
|
||||
.open(mount_point.path().join("etc/locale.gen"))
|
||||
.and_then(|mut locale_gen| locale_gen.write_all(b"en_US.UTF-8 UTF-8\n"))
|
||||
.context("Failed to create locale.gen")?;
|
||||
fs::write(
|
||||
mount_point.path().join("etc/locale.conf"),
|
||||
"LANG=en_US.UTF-8",
|
||||
)
|
||||
.context("Failed to write to locale.conf")?;
|
||||
arch_chroot
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.arg("locale-gen")
|
||||
.run()
|
||||
.context("locale-gen failed")?;
|
||||
|
||||
arch_chroot
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.args(&[
|
||||
"sed",
|
||||
"-i",
|
||||
"s/# %wheel ALL=(ALL) NOPASSWD: ALL/aur ALL=(ALL) NOPASSWD: ALL/g",
|
||||
])
|
||||
.arg("/etc/sudoers")
|
||||
.run()
|
||||
.context("Failed to modify sudoers file for AUR packages")?;
|
||||
info!("Installing AUR packages");
|
||||
|
||||
arch_chroot
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.args(&["sudo", "-u", "aur"])
|
||||
.arg("git")
|
||||
.arg("clone")
|
||||
.arg(format!(
|
||||
"https://aur.archlinux.org/{}.git",
|
||||
arch_chroot
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.args(&["useradd", "-m", "aur"])
|
||||
.run()
|
||||
.context("Failed to create temporary user to install AUR packages")?;
|
||||
|
||||
let aur_sudoers = mount_point.path().join("etc/sudoers.d/aur");
|
||||
fs::write(&aur_sudoers, "aur ALL=(ALL) NOPASSWD: ALL")
|
||||
.context("Failed to modify sudoers file for AUR packages")?;
|
||||
|
||||
arch_chroot
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.args(&["sudo", "-u", "aur"])
|
||||
.arg("git")
|
||||
.arg("clone")
|
||||
.arg(format!(
|
||||
"https://aur.archlinux.org/{}.git",
|
||||
&command.aur_helper.package_name
|
||||
))
|
||||
.arg(format!("/home/aur/{}", &command.aur_helper.name))
|
||||
.run()
|
||||
.context("Failed to clone AUR helper package")?;
|
||||
|
||||
arch_chroot
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.args(&[
|
||||
"bash",
|
||||
"-c",
|
||||
&format!(
|
||||
"cd /home/aur/{} && sudo -u aur makepkg -s -i --noconfirm",
|
||||
&command.aur_helper.name
|
||||
))
|
||||
.arg(format!("/home/aur/{}", &command.aur_helper.name))
|
||||
.run()
|
||||
.context("Failed to clone AUR helper package")?;
|
||||
),
|
||||
])
|
||||
.run()
|
||||
.context("Failed to build AUR helper")?;
|
||||
|
||||
arch_chroot
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.args(&[
|
||||
"bash",
|
||||
"-c",
|
||||
&format!(
|
||||
"cd /home/aur/{} && sudo -u aur makepkg -s -i --noconfirm",
|
||||
&command.aur_helper.name
|
||||
),
|
||||
])
|
||||
.run()
|
||||
.context("Failed to build AUR helper")?;
|
||||
arch_chroot
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.args(&["sudo", "-u", "aur"])
|
||||
.args(&command.aur_helper.install_command)
|
||||
.args(aur_pacakges)
|
||||
.run()
|
||||
.context("Failed to install AUR packages")?;
|
||||
|
||||
arch_chroot
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.args(&["sudo", "-u", "aur"])
|
||||
.args(&command.aur_helper.install_command)
|
||||
.args(presets.aur_packages)
|
||||
.args(&command.aur_packages)
|
||||
.run()
|
||||
.context("Failed to install AUR packages")?;
|
||||
// Clean up aur user:
|
||||
arch_chroot
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.args(&["userdel", "-r", "aur"])
|
||||
.run()
|
||||
.context("Failed to delete temporary aur user")?;
|
||||
|
||||
// Clean up aur user:
|
||||
arch_chroot
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.args(&["userdel", "-r", "aur"])
|
||||
.run()
|
||||
.context("Failed to delete temporary aur user")?;
|
||||
fs::remove_file(&aur_sudoers).context("Cannot delete the AUR sudoers temporary file")?;
|
||||
|
||||
arch_chroot
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.args(&[
|
||||
"sed",
|
||||
"-i",
|
||||
"s/aur ALL=(ALL) NOPASSWD: ALL/# %wheel ALL=(ALL) NOPASSWD: ALL/g",
|
||||
])
|
||||
.arg("/etc/sudoers")
|
||||
.run()
|
||||
.context("Failed to undo sudoers changes")?;
|
||||
}
|
||||
if !presets.scripts.is_empty() {
|
||||
info!("Running custom scripts");
|
||||
}
|
||||
@@ -387,7 +405,7 @@ fn create(command: args::CreateCommand) -> anyhow::Result<()> {
|
||||
),
|
||||
)
|
||||
.run()
|
||||
.context("Failed running preset script")?;
|
||||
.with_context(|| format!("Failed running preset script:\n{}", script.script_text))?;
|
||||
}
|
||||
|
||||
info!("Performing post installation tasks");
|
||||
@@ -406,25 +424,6 @@ fn create(command: args::CreateCommand) -> anyhow::Result<()> {
|
||||
)
|
||||
.context("Failed to write to journald.conf")?;
|
||||
|
||||
info!("Setting locale");
|
||||
fs::OpenOptions::new()
|
||||
.append(true)
|
||||
.write(true)
|
||||
.open(mount_point.path().join("etc/locale.gen"))
|
||||
.and_then(|mut locale_gen| locale_gen.write_all(b"en_US.UTF-8 UTF-8\n"))
|
||||
.context("Failed to create locale.gen")?;
|
||||
fs::write(
|
||||
mount_point.path().join("etc/locale.conf"),
|
||||
"LANG=en_US.UTF-8",
|
||||
)
|
||||
.context("Failed to write to locale.conf")?;
|
||||
arch_chroot
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.arg("locale-gen")
|
||||
.run()
|
||||
.context("locale-gen failed")?;
|
||||
|
||||
info!("Generating initramfs");
|
||||
fs::write(
|
||||
mount_point.path().join("etc/mkinitcpio.conf"),
|
||||
@@ -472,6 +471,23 @@ fn create(command: args::CreateCommand) -> anyhow::Result<()> {
|
||||
.arg(format!("grub-install --target=i386-pc --boot-directory /boot {} && grub-install --target=x86_64-efi --efi-directory /boot --boot-directory /boot --removable && grub-mkconfig -o /boot/grub/grub.cfg", disk_path.display()))
|
||||
.run().context("Failed to install grub")?;
|
||||
|
||||
let bootloader = mount_point.path().join("boot/EFI/BOOT/BOOTX64.efi");
|
||||
fs::rename(
|
||||
&bootloader,
|
||||
mount_point.path().join("boot/EFI/BOOT/grubx64.efi"),
|
||||
)
|
||||
.context("Cannot move out grub")?;
|
||||
fs::copy(
|
||||
mount_point.path().join("usr/share/shim-signed/mmx64.efi"),
|
||||
mount_point.path().join("boot/EFI/BOOT/mmx64.efi"),
|
||||
)
|
||||
.context("Failed copying mmx64")?;
|
||||
fs::copy(
|
||||
mount_point.path().join("usr/share/shim-signed/shimx64.efi"),
|
||||
bootloader,
|
||||
)
|
||||
.context("Failed copying shim")?;
|
||||
|
||||
debug!(
|
||||
"GRUB configuration: {}",
|
||||
fs::read_to_string(mount_point.path().join("boot/grub/grub.cfg"))
|
||||
|
||||
@@ -33,7 +33,7 @@ fn visit_dirs(dir: &Path, filevec: &mut Vec<PathBuf>) -> Result<(), io::Error> {
|
||||
impl Preset {
|
||||
fn load(path: &Path) -> anyhow::Result<Self> {
|
||||
let data = fs::read_to_string(path).with_context(|| format!("{}", path.display()))?;
|
||||
Ok(toml::from_str(&data).with_context(|| format!("{}", path.display()))?)
|
||||
toml::from_str(&data).with_context(|| format!("{}", path.display()))
|
||||
}
|
||||
|
||||
fn process(
|
||||
@@ -41,7 +41,7 @@ impl Preset {
|
||||
packages: &mut HashSet<String>,
|
||||
scripts: &mut Vec<Script>,
|
||||
environment_variables: &mut HashSet<String>,
|
||||
path: &PathBuf,
|
||||
path: &Path,
|
||||
aur_packages: &mut HashSet<String>,
|
||||
) -> anyhow::Result<()> {
|
||||
if let Some(preset_packages) = &self.packages {
|
||||
@@ -111,7 +111,7 @@ impl PresetsCollection {
|
||||
// Build vector of paths to files, then sort by path name
|
||||
// Recursively load directories of preset files
|
||||
let mut dir_paths: Vec<PathBuf> = Vec::new();
|
||||
visit_dirs(&preset, &mut dir_paths)
|
||||
visit_dirs(preset, &mut dir_paths)
|
||||
.with_context(|| format!("{}", preset.display()))?;
|
||||
|
||||
// Order not guaranteed so we sort
|
||||
@@ -128,11 +128,11 @@ impl PresetsCollection {
|
||||
)?;
|
||||
}
|
||||
} else {
|
||||
Preset::load(&preset)?.process(
|
||||
Preset::load(preset)?.process(
|
||||
&mut packages,
|
||||
&mut scripts,
|
||||
&mut environment_variables,
|
||||
&preset,
|
||||
preset,
|
||||
&mut aur_packages,
|
||||
)?;
|
||||
}
|
||||
@@ -151,8 +151,8 @@ impl PresetsCollection {
|
||||
|
||||
Ok(Self {
|
||||
packages,
|
||||
scripts,
|
||||
aur_packages,
|
||||
scripts,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ impl LoopDevice {
|
||||
);
|
||||
info!("Mounted {} to {}", file.display(), path.display());
|
||||
|
||||
Ok(LoopDevice { path, losetup })
|
||||
Ok(Self { path, losetup })
|
||||
}
|
||||
|
||||
pub fn path(&self) -> &Path {
|
||||
|
||||
@@ -68,7 +68,7 @@ pub fn get_storage_devices(allow_non_removable: bool) -> anyhow::Result<Vec<Devi
|
||||
.context("Could not parse block size to unsigned integer (u128)")?
|
||||
* 512,
|
||||
),
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
|
||||
@@ -21,7 +21,7 @@ impl<'a> StorageDevice<'a> {
|
||||
.context("Error querying information about the block device")?;
|
||||
let device_name = path
|
||||
.file_name()
|
||||
.and_then(|s| s.to_str())
|
||||
.and_then(std::ffi::OsStr::to_str)
|
||||
.map(String::from)
|
||||
.ok_or_else(|| anyhow!("Invalid device name: {}", path.display()))?;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ mod chroot;
|
||||
mod mount;
|
||||
mod qemu;
|
||||
|
||||
use anyhow::Context;
|
||||
pub use chroot::chroot;
|
||||
pub use mount::mount;
|
||||
pub use qemu::qemu;
|
||||
@@ -17,7 +18,9 @@ pub struct Tool {
|
||||
|
||||
impl Tool {
|
||||
pub fn find(name: &'static str) -> anyhow::Result<Self> {
|
||||
Ok(Self { exec: which(name)? })
|
||||
Ok(Self {
|
||||
exec: which(name).context(format!("Cannot find {}", name))?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn execute(&self) -> Command {
|
||||
|
||||
@@ -20,7 +20,7 @@ pub fn mount<'a>(
|
||||
|
||||
info!("Mounting filesystems to {}", mount_path.display());
|
||||
mount_stack
|
||||
.mount(&root_filesystem, mount_path.into(), None)
|
||||
.mount(root_filesystem, mount_path.into(), None)
|
||||
.with_context(|| format!("Error mounting filesystem to {}", mount_path.display()))?;
|
||||
|
||||
let boot_point = mount_path.join("boot");
|
||||
@@ -29,7 +29,7 @@ pub fn mount<'a>(
|
||||
}
|
||||
|
||||
mount_stack
|
||||
.mount(&boot_filesystem, boot_point, None)
|
||||
.mount(boot_filesystem, boot_point, None)
|
||||
.context("Error mounting the boot point")?;
|
||||
|
||||
Ok(mount_stack)
|
||||
|
||||
Reference in New Issue
Block a user