mirror of
https://github.com/philmmanjaro/alma.git
synced 2025-07-25 22:49:28 +02:00
Recursively import presets from provided directory (#33)
Allow a directory to be passed as a preset, in which case all files inside the directory (recursively) are treated as presets, loaded in lexicographical order. This allows one to compose a system by mixing in different presets, and easily change their order of execution.
This commit is contained in:
parent
6624f05d1e
commit
1f5b28c065
15
README.md
15
README.md
@ -100,12 +100,25 @@ Preset files are simple TOML files which contain:
|
||||
|
||||
See the presets directory for examples.
|
||||
|
||||
Presets are used via the `--presets` argument (multiple preset files may be provided):
|
||||
Presets are used via the `--presets` argument (multiple preset files or directories may be provided):
|
||||
|
||||
``` shell
|
||||
sudo ALMA_USER=archie alma create /dev/disk/by-id/usb-Generic_USB_Flash_Disk-0:0 --presets ./presets/user.toml ./presets/custom_preset.toml
|
||||
```
|
||||
|
||||
If a directory is provided, then all files and subdirectories in the directory are recursively crawled in alphanumeric order (all files must be ALMA .toml files). This allows you to use the following structure to compose many scripts in a specific order:
|
||||
|
||||
```
|
||||
.
|
||||
├── 00-add_user.toml
|
||||
├── 01-xorg
|
||||
│ ├── 00-install.toml
|
||||
│ └── 01-config.toml
|
||||
└── 02-i3
|
||||
├── 00-install.toml
|
||||
└── 01-copy_dotfiles.toml
|
||||
```
|
||||
|
||||
Example preset TOML:
|
||||
|
||||
``` toml
|
||||
|
@ -37,7 +37,7 @@ pub struct CreateCommand {
|
||||
#[structopt(parse(from_os_str))]
|
||||
pub path: Option<PathBuf>,
|
||||
|
||||
/// Additional pacakges to install
|
||||
/// Additional packages to install
|
||||
#[structopt(short = "p", long = "extra-packages", value_name = "package")]
|
||||
pub extra_packages: Vec<String>,
|
||||
|
||||
|
@ -4,6 +4,7 @@ use serde::Deserialize;
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@ -13,6 +14,21 @@ struct Preset {
|
||||
environment_variables: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
fn visit_dirs(dir: &Path, filevec: &mut Vec<PathBuf>) -> Result<(), io::Error> {
|
||||
if dir.is_dir() {
|
||||
for entry in fs::read_dir(dir)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
if path.is_dir() {
|
||||
visit_dirs(&path, filevec)?;
|
||||
} else {
|
||||
filevec.push(entry.path());
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl Preset {
|
||||
fn load(path: &Path) -> Result<Self, Error> {
|
||||
let data = fs::read_to_string(path)
|
||||
@ -20,6 +36,23 @@ impl Preset {
|
||||
Ok(toml::from_str(&data)
|
||||
.with_context(|_| ErrorKind::Preset(format!("{}", path.display())))?)
|
||||
}
|
||||
|
||||
fn process(
|
||||
&self,
|
||||
packages: &mut HashSet<String>,
|
||||
scripts: &mut Vec<String>,
|
||||
environment_variables: &mut HashSet<String>,
|
||||
) {
|
||||
if let Some(preset_packages) = &self.packages {
|
||||
packages.extend(preset_packages.clone());
|
||||
}
|
||||
|
||||
if let Some(preset_environment_variables) = &self.environment_variables {
|
||||
environment_variables.extend(preset_environment_variables.clone());
|
||||
}
|
||||
|
||||
scripts.extend(self.script.clone());
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PresetsCollection {
|
||||
@ -34,21 +67,31 @@ impl PresetsCollection {
|
||||
let mut environment_variables = HashSet::new();
|
||||
|
||||
for preset in list {
|
||||
let Preset {
|
||||
script,
|
||||
packages: preset_packages,
|
||||
environment_variables: preset_environment_variables,
|
||||
} = Preset::load(&preset)?;
|
||||
if preset.is_dir() {
|
||||
// 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)
|
||||
.with_context(|_| ErrorKind::Preset(format!("{}", preset.display())))?;
|
||||
|
||||
if let Some(preset_packages) = preset_packages {
|
||||
packages.extend(preset_packages);
|
||||
// Order not guaranteed so we sort
|
||||
// In the future may want to support numerical sort i.e. 15_... < 100_...
|
||||
dir_paths.sort();
|
||||
|
||||
for path in dir_paths {
|
||||
Preset::load(&path)?.process(
|
||||
&mut packages,
|
||||
&mut scripts,
|
||||
&mut environment_variables,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
Preset::load(&preset)?.process(
|
||||
&mut packages,
|
||||
&mut scripts,
|
||||
&mut environment_variables,
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(preset_environment_variables) = preset_environment_variables {
|
||||
environment_variables.extend(preset_environment_variables);
|
||||
}
|
||||
|
||||
scripts.extend(script);
|
||||
}
|
||||
|
||||
let missing_envrionments: Vec<String> = environment_variables
|
||||
|
Loading…
x
Reference in New Issue
Block a user