Add presets support
This commit is contained in:
parent
91215703bf
commit
ffbd34e14f
31
Cargo.lock
generated
31
Cargo.lock
generated
@ -7,9 +7,11 @@ dependencies = [
|
|||||||
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -397,6 +399,24 @@ name = "scoped_threadpool"
|
|||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "simplelog"
|
name = "simplelog"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
@ -505,6 +525,14 @@ dependencies = [
|
|||||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "unicode-segmentation"
|
name = "unicode-segmentation"
|
||||||
version = "1.3.0"
|
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 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 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 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 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 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"
|
"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 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 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 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-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-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"
|
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||||
|
@ -12,3 +12,5 @@ structopt = "0.2.14"
|
|||||||
simplelog = "0.5.3"
|
simplelog = "0.5.3"
|
||||||
tempfile = "3.0.5"
|
tempfile = "3.0.5"
|
||||||
nix = "0.12.0"
|
nix = "0.12.0"
|
||||||
|
serde = { version = "1.0.92", features = ["derive"] }
|
||||||
|
toml = "0.5.1"
|
||||||
|
@ -41,6 +41,10 @@ pub struct CreateCommand {
|
|||||||
/// Encrypt the root partition
|
/// Encrypt the root partition
|
||||||
#[structopt(short = "e", long = "encrypted-root")]
|
#[structopt(short = "e", long = "encrypted-root")]
|
||||||
pub encrypted_root: bool,
|
pub encrypted_root: bool,
|
||||||
|
|
||||||
|
/// Path to preset files
|
||||||
|
#[structopt(long = "presets")]
|
||||||
|
pub presets: Vec<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(StructOpt)]
|
#[derive(StructOpt)]
|
||||||
|
@ -6,7 +6,7 @@ pub struct Error {
|
|||||||
inner: Context<ErrorKind>,
|
inner: Context<ErrorKind>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)]
|
#[derive(Clone, Eq, PartialEq, Debug, Fail)]
|
||||||
pub enum ErrorKind {
|
pub enum ErrorKind {
|
||||||
#[fail(display = "Error quering information about the block device")]
|
#[fail(display = "Error quering information about the block device")]
|
||||||
DeviceQuery,
|
DeviceQuery,
|
||||||
@ -73,6 +73,12 @@ pub enum ErrorKind {
|
|||||||
|
|
||||||
#[fail(display = "Failed launching Qemu")]
|
#[fail(display = "Failed launching Qemu")]
|
||||||
Qemu,
|
Qemu,
|
||||||
|
|
||||||
|
#[fail(display = "Error loading preset \"{}\"", _0)]
|
||||||
|
Preset(String),
|
||||||
|
|
||||||
|
#[fail(display = "Error executing preset script")]
|
||||||
|
PresetScript,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Fail for Error {
|
impl Fail for Error {
|
||||||
|
56
src/main.rs
56
src/main.rs
@ -1,5 +1,6 @@
|
|||||||
mod args;
|
mod args;
|
||||||
mod error;
|
mod error;
|
||||||
|
mod presets;
|
||||||
mod process;
|
mod process;
|
||||||
mod storage;
|
mod storage;
|
||||||
mod tool;
|
mod tool;
|
||||||
@ -13,9 +14,10 @@ use failure::{Fail, ResultExt};
|
|||||||
use log::{debug, error, info, warn};
|
use log::{debug, error, info, warn};
|
||||||
use nix::sys::signal;
|
use nix::sys::signal;
|
||||||
use simplelog::*;
|
use simplelog::*;
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::Write;
|
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::path::Path;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
@ -74,6 +76,8 @@ fn fix_fstab(fstab: &str) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create(command: CreateCommand) -> Result<(), Error> {
|
fn create(command: CreateCommand) -> Result<(), Error> {
|
||||||
|
let presets = presets::Presets::load(&command.presets)?;
|
||||||
|
|
||||||
let sgdisk = Tool::find("sgdisk")?;
|
let sgdisk = Tool::find("sgdisk")?;
|
||||||
let pacstrap = Tool::find("pacstrap")?;
|
let pacstrap = Tool::find("pacstrap")?;
|
||||||
let arch_chroot = Tool::find("arch-chroot")?;
|
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 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");
|
info!("Bootstrapping system");
|
||||||
pacstrap
|
pacstrap
|
||||||
.execute()
|
.execute()
|
||||||
.arg("-c")
|
.arg("-c")
|
||||||
.arg(mount_point.path())
|
.arg(mount_point.path())
|
||||||
.args(&[
|
.args(packages)
|
||||||
"base",
|
|
||||||
"grub",
|
|
||||||
"efibootmgr",
|
|
||||||
"intel-ucode",
|
|
||||||
"networkmanager",
|
|
||||||
"broadcom-wl",
|
|
||||||
])
|
|
||||||
.args(&command.extra_packages)
|
.args(&command.extra_packages)
|
||||||
.run(ErrorKind::Pacstrap)?;
|
.run(ErrorKind::Pacstrap)?;
|
||||||
|
|
||||||
@ -167,6 +178,33 @@ fn create(command: CreateCommand) -> Result<(), Error> {
|
|||||||
debug!("fstab:\n{}", fstab);
|
debug!("fstab:\n{}", fstab);
|
||||||
fs::write(mount_point.path().join("etc/fstab"), fstab).context(ErrorKind::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
|
arch_chroot
|
||||||
.execute()
|
.execute()
|
||||||
.arg(mount_point.path())
|
.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 {
|
impl CommandExt for Command {
|
||||||
fn run(&mut self, context: ErrorKind) -> Result<(), Error> {
|
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() {
|
if !exit_status.success() {
|
||||||
return Err(ProcessError::BadExitCode(exit_status)
|
Err(ProcessError::BadExitCode(exit_status)).with_context(|_| context.clone())?;
|
||||||
.context(context)
|
|
||||||
.into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_text_output(&mut self, context: ErrorKind) -> Result<String, Error> {
|
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() {
|
if !output.status.success() {
|
||||||
let error = str::from_utf8(&output.stderr).unwrap_or("[INVALID UTF8]");
|
let error = str::from_utf8(&output.stderr).unwrap_or("[INVALID UTF8]");
|
||||||
error!("{}", error);
|
error!("{}", error);
|
||||||
return Err(ProcessError::BadExitCode(output.status)
|
Err(ProcessError::BadExitCode(output.status)).with_context(|_| context.clone())?;
|
||||||
.context(context)
|
|
||||||
.into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(String::from(
|
Ok(String::from(
|
||||||
str::from_utf8(&output.stdout)
|
str::from_utf8(&output.stdout)
|
||||||
.map_err(|_| ProcessError::InvalidUtf8)
|
.map_err(|_| ProcessError::InvalidUtf8)
|
||||||
.context(context)?,
|
.with_context(|_| context.clone())?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user