build.rs/src/task.rs

146 lines
4.6 KiB
Rust

use std::path::{Path, PathBuf};
use std::ffi::OsString;
use std::collections::HashMap;
use std::process::Command;
//use crate::log;
use crate::dvcs;
use crate::db;
use crate::db::{Entry,is_executable};
#[derive(Debug)]
pub struct Task {
pub name: OsString,
pub bin: PathBuf,
pub source: Option<String>,
pub dvcs: dvcs::Backend,
pub config: HashMap<String, String>,
pub branch: Option<String>,
pub hosts: Vec<String>,
pub cloned: bool,
}
/// config returns an option of (settings directory, ignored tasks) as
/// (PathBuf, Vec<String>)
pub fn config(basedir: &Path) -> (PathBuf, Vec<String>) {
let hostname = std::env::var("HOST").unwrap_or_else(
|_| hostname::get().unwrap().into_string().unwrap()
);
let path = basedir.join(hostname);
if path.is_dir() {
let ignored = path.read_dir().unwrap().filter_map(|x| {
if x.is_err() { return None; }
let mut name = x.unwrap().file_name().into_string().unwrap();
if name.ends_with(".ignore") {
return Some(name.trim_end_matches(".ignore").to_string());
}
return None;
}).collect();
(path, ignored)
} else {
// TODO: load .ignore in default config?
(basedir.join("config"), Vec::new())
}
}
impl Task {
pub fn from_entry(entry: &Entry) -> Task {
let source = entry.read_setting("source");
let cloned = source.clone().map_or(false, |_| {
let mut path = entry.base_dir.clone();
path.push(format!(".{}", entry.name.to_str().expect("WTF")));
path.is_dir()
});
Task {
name: entry.name.clone(),
bin: entry.path.clone(),
source,
dvcs: dvcs::from_setting(entry.read_setting("dvcs")),
config: HashMap::new(),
branch: entry.read_setting("branch"),
hosts: entry.read_setting("hosts").map_or(Vec::new(), |c| c.split("\n").map(|line| line.to_string()).collect()),
cloned,
}
}
pub fn run_on_host(&self) -> bool {
println!("{:#?}", self.hosts);
if self.hosts.len() == 0 {
return true;
}
// $HOSTNAME env is a bashism, we need to call libc (through hostname crate)
// to find out the actual hostname
let hostname = std::env::var("HOST").unwrap_or_else(
|_| hostname::get().unwrap().into_string().unwrap()
);
println!("HOSTNAME: {}", hostname);
if self.hosts.contains(&hostname) {
return true;
}
return false;
}
pub fn run(&self) {
if !self.run_on_host() { return; }
let cmd_out = Command::new("bash")
.arg(&self.bin)
.arg(&self.name)
.output()
.expect(&format!("Failed to run {:?}", &self.bin));
let mut log_path = self.bin.clone();
log_path.set_extension("log");
std::fs::write(&log_path, cmd_out.stderr).expect(&format!("Failed to write log to {:?}", &log_path));
}
pub fn run_once(&self) {
if !self.run_on_host() { return; }
let mut done_path = self.bin.clone();
done_path.set_extension("done");
if !done_path.exists() {
self.run();
std::fs::write(&done_path, "");
}
}
}
// Takes an already instanced database (ie Vec<Entry>)
// to turn into a dictionary of Tasks
pub fn from_entries(db: Vec<Entry>) -> HashMap<String, Task> {
let mut res: HashMap<String, Task> = HashMap::new();
for entry in db {
let task = Task::from_entry(&entry);
res.insert(
task.name.clone().into_string().expect("Failed to convert"),
task
);
}
return res;
}
/// Returns a hashmap of tasks, or std::io::Error
/// Reads all entries in a directory
pub fn from_dir(base_dir: &str) -> Result<HashMap<String, Task>, std::io::Error> {
Ok(from_entries(
db::from(base_dir, is_executable)?
))
}
/// Returns a hashmap of tasks, or std::io::Error
/// Reads entries in a given list from a directory, fails if a requested entry doesn't exist
/// (does not load the whole folder)
pub fn from_dir_and_list(basedir: &str, list: Vec<String>) -> Result<HashMap<String, Task>, db::Error> {
let mut entries: HashMap<String, Task> = HashMap::new();
for item in list {
if let Some(entry) = db::entry(&basedir, is_executable, &item) {
entries.insert(item.clone(), Task::from_entry(&entry));
} else {
return Err(db::Error::EntryNotFound(item.clone()))
}
}
Ok(
entries
)
}