mirror of
https://github.com/philmmanjaro/alma.git
synced 2025-12-06 19:29:21 +01:00
Add presets support
This commit is contained in:
@@ -41,6 +41,10 @@ pub struct CreateCommand {
|
||||
/// Encrypt the root partition
|
||||
#[structopt(short = "e", long = "encrypted-root")]
|
||||
pub encrypted_root: bool,
|
||||
|
||||
/// Path to preset files
|
||||
#[structopt(long = "presets")]
|
||||
pub presets: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(StructOpt)]
|
||||
|
||||
@@ -6,7 +6,7 @@ pub struct Error {
|
||||
inner: Context<ErrorKind>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)]
|
||||
#[derive(Clone, Eq, PartialEq, Debug, Fail)]
|
||||
pub enum ErrorKind {
|
||||
#[fail(display = "Error quering information about the block device")]
|
||||
DeviceQuery,
|
||||
@@ -73,6 +73,12 @@ pub enum ErrorKind {
|
||||
|
||||
#[fail(display = "Failed launching Qemu")]
|
||||
Qemu,
|
||||
|
||||
#[fail(display = "Error loading preset \"{}\"", _0)]
|
||||
Preset(String),
|
||||
|
||||
#[fail(display = "Error executing preset script")]
|
||||
PresetScript,
|
||||
}
|
||||
|
||||
impl Fail for Error {
|
||||
|
||||
56
src/main.rs
56
src/main.rs
@@ -1,5 +1,6 @@
|
||||
mod args;
|
||||
mod error;
|
||||
mod presets;
|
||||
mod process;
|
||||
mod storage;
|
||||
mod tool;
|
||||
@@ -13,9 +14,10 @@ use failure::{Fail, ResultExt};
|
||||
use log::{debug, error, info, warn};
|
||||
use nix::sys::signal;
|
||||
use simplelog::*;
|
||||
use std::collections::HashSet;
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
use std::os::unix::process::CommandExt as UnixCommandExt;
|
||||
use std::os::unix::{fs::PermissionsExt, process::CommandExt as UnixCommandExt};
|
||||
use std::path::Path;
|
||||
use std::process::exit;
|
||||
use std::thread;
|
||||
@@ -74,6 +76,8 @@ fn fix_fstab(fstab: &str) -> String {
|
||||
}
|
||||
|
||||
fn create(command: CreateCommand) -> Result<(), Error> {
|
||||
let presets = presets::Presets::load(&command.presets)?;
|
||||
|
||||
let sgdisk = Tool::find("sgdisk")?;
|
||||
let pacstrap = Tool::find("pacstrap")?;
|
||||
let arch_chroot = Tool::find("arch-chroot")?;
|
||||
@@ -141,19 +145,26 @@ fn create(command: CreateCommand) -> Result<(), Error> {
|
||||
|
||||
let mount_stack = mount(mount_point.path(), &boot_filesystem, &root_filesystem)?;
|
||||
|
||||
let mut packages: HashSet<String> = [
|
||||
"base",
|
||||
"grub",
|
||||
"efibootmgr",
|
||||
"intel-ucode",
|
||||
"networkmanager",
|
||||
"broadcom-wl",
|
||||
]
|
||||
.iter()
|
||||
.map(|s| String::from(*s))
|
||||
.collect();
|
||||
|
||||
packages.extend(presets.packages);
|
||||
|
||||
info!("Bootstrapping system");
|
||||
pacstrap
|
||||
.execute()
|
||||
.arg("-c")
|
||||
.arg(mount_point.path())
|
||||
.args(&[
|
||||
"base",
|
||||
"grub",
|
||||
"efibootmgr",
|
||||
"intel-ucode",
|
||||
"networkmanager",
|
||||
"broadcom-wl",
|
||||
])
|
||||
.args(packages)
|
||||
.args(&command.extra_packages)
|
||||
.run(ErrorKind::Pacstrap)?;
|
||||
|
||||
@@ -167,6 +178,33 @@ fn create(command: CreateCommand) -> Result<(), Error> {
|
||||
debug!("fstab:\n{}", fstab);
|
||||
fs::write(mount_point.path().join("etc/fstab"), fstab).context(ErrorKind::Fstab)?;
|
||||
|
||||
if !presets.scripts.is_empty() {
|
||||
info!("Running custom scripts");
|
||||
}
|
||||
|
||||
for script in presets.scripts {
|
||||
let mut script_file =
|
||||
tempfile::NamedTempFile::new_in(mount_point.path()).context(ErrorKind::PresetScript)?;
|
||||
script_file
|
||||
.write_all(script.as_bytes())
|
||||
.and_then(|_| script_file.as_file_mut().metadata())
|
||||
.and_then(|metadata| {
|
||||
let mut permissions = metadata.permissions();
|
||||
permissions.set_mode(0o755);
|
||||
fs::set_permissions(script_file.path(), permissions)
|
||||
})
|
||||
.context(ErrorKind::PresetScript)?;
|
||||
|
||||
let script_path = script_file.into_temp_path();
|
||||
arch_chroot
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
.arg(Path::new("/").join(script_path.file_name().unwrap()))
|
||||
.run(ErrorKind::PostInstallation)?;
|
||||
}
|
||||
|
||||
info!("Performing post installation tasks");
|
||||
|
||||
arch_chroot
|
||||
.execute()
|
||||
.arg(mount_point.path())
|
||||
|
||||
50
src/presets.rs
Normal file
50
src/presets.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
use crate::error::{Error, ErrorKind};
|
||||
use failure::ResultExt;
|
||||
use serde::Deserialize;
|
||||
use std::collections::HashSet;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use toml;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
||||
struct Preset {
|
||||
packages: Option<Vec<String>>,
|
||||
script: Option<String>,
|
||||
}
|
||||
|
||||
impl Preset {
|
||||
fn load(path: &Path) -> Result<Self, Error> {
|
||||
let data = fs::read_to_string(path)
|
||||
.with_context(|_| ErrorKind::Preset(format!("{}", path.display())))?;
|
||||
Ok(toml::from_str(&data)
|
||||
.with_context(|_| ErrorKind::Preset(format!("{}", path.display())))?)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Presets {
|
||||
pub packages: HashSet<String>,
|
||||
pub scripts: Vec<String>,
|
||||
}
|
||||
|
||||
impl Presets {
|
||||
pub fn load(list: &[PathBuf]) -> Result<Self, Error> {
|
||||
let mut packages = HashSet::new();
|
||||
let mut scripts = Vec::new();
|
||||
|
||||
for preset in list {
|
||||
let Preset {
|
||||
script,
|
||||
packages: preset_packages,
|
||||
} = Preset::load(&preset)?;
|
||||
|
||||
if let Some(preset_packages) = preset_packages {
|
||||
packages.extend(preset_packages);
|
||||
}
|
||||
|
||||
scripts.extend(script);
|
||||
}
|
||||
|
||||
Ok(Self { packages, scripts })
|
||||
}
|
||||
}
|
||||
@@ -20,32 +20,32 @@ pub trait CommandExt {
|
||||
|
||||
impl CommandExt for Command {
|
||||
fn run(&mut self, context: ErrorKind) -> Result<(), Error> {
|
||||
let exit_status = self.spawn().context(context)?.wait().context(context)?;
|
||||
let exit_status = self
|
||||
.spawn()
|
||||
.with_context(|_| context.clone())?
|
||||
.wait()
|
||||
.with_context(|_| context.clone())?;
|
||||
|
||||
if !exit_status.success() {
|
||||
return Err(ProcessError::BadExitCode(exit_status)
|
||||
.context(context)
|
||||
.into());
|
||||
Err(ProcessError::BadExitCode(exit_status)).with_context(|_| context.clone())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_text_output(&mut self, context: ErrorKind) -> Result<String, Error> {
|
||||
let output = self.output().context(context)?;
|
||||
let output = self.output().with_context(|_| context.clone())?;
|
||||
|
||||
if !output.status.success() {
|
||||
let error = str::from_utf8(&output.stderr).unwrap_or("[INVALID UTF8]");
|
||||
error!("{}", error);
|
||||
return Err(ProcessError::BadExitCode(output.status)
|
||||
.context(context)
|
||||
.into());
|
||||
Err(ProcessError::BadExitCode(output.status)).with_context(|_| context.clone())?;
|
||||
}
|
||||
|
||||
Ok(String::from(
|
||||
str::from_utf8(&output.stdout)
|
||||
.map_err(|_| ProcessError::InvalidUtf8)
|
||||
.context(context)?,
|
||||
.with_context(|_| context.clone())?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user