Add presets support

This commit is contained in:
Roey Darwish Dror 2019-06-05 10:05:59 +03:00
parent 91215703bf
commit ffbd34e14f
7 changed files with 150 additions and 19 deletions

31
Cargo.lock generated
View File

@ -7,9 +7,11 @@ dependencies = [
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
"simplelog 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -397,6 +399,24 @@ name = "scoped_threadpool"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "simplelog"
version = "0.5.3"
@ -505,6 +525,14 @@ dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "toml"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-segmentation"
version = "1.3.0"
@ -606,6 +634,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
"checksum rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc78bfd5acd7bf3e89cffcf899e5cb1a52d6fafa8dec2739ad70c9577a57288"
"checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
"checksum serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "32746bf0f26eab52f06af0d0aa1984f641341d06d8d673c693871da2d188c9be"
"checksum serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "46a3223d0c9ba936b61c0d2e3e559e3217dbfb8d65d06d26e8b3c25de38bae3e"
"checksum simplelog 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e95345f185d5adeb8ec93459d2dc99654e294cc6ccf5b75414d8ea262de9a13"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3d0760c312538987d363c36c42339b55f5ee176ea8808bbe4543d484a291c8d1"
@ -617,6 +647,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
"checksum toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8c96d7873fa7ef8bdeb3a9cda3ac48389b4154f32b9803b4bc26220b677b039"
"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"

View File

@ -12,3 +12,5 @@ structopt = "0.2.14"
simplelog = "0.5.3"
tempfile = "3.0.5"
nix = "0.12.0"
serde = { version = "1.0.92", features = ["derive"] }
toml = "0.5.1"

View File

@ -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)]

View File

@ -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 {

View File

@ -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
View 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 })
}
}

View File

@ -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())?,
))
}
}