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:
James McMurray
2020-03-21 06:16:15 +01:00
committed by GitHub
parent 6624f05d1e
commit 1f5b28c065
3 changed files with 71 additions and 15 deletions

View File

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

View File

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