173 lines
5.5 KiB
Rust
173 lines
5.5 KiB
Rust
use std::path::{Path, PathBuf};
|
|
use std::collections::HashMap;
|
|
use std::process::Command;
|
|
|
|
use crate::dvcs;
|
|
use crate::dvcs::{Backend,Repo};
|
|
use crate::db;
|
|
use crate::db::{Entry,is_executable};
|
|
use crate::log;
|
|
|
|
#[derive(Debug)]
|
|
pub struct Task {
|
|
pub name: String,
|
|
pub bin: PathBuf,
|
|
pub source: Option<String>,
|
|
pub repo: Option<Repo>,
|
|
pub config: HashMap<String, String>,
|
|
pub branch: Option<String>,
|
|
pub hosts: Vec<String>,
|
|
pub cloned: bool,
|
|
pub subupdates: 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 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 dest = entry.base_dir.join(&format!(".{}", entry.name.to_str().expect("WTF")));
|
|
let cloned = source.clone().map_or(false, |_| {
|
|
dest.is_dir()
|
|
});
|
|
let subupdates = entry.read_setting("subupdates").is_some();
|
|
let dvcs = dvcs::from_setting(entry.read_setting("dvcs"));
|
|
|
|
Task {
|
|
name: entry.name.to_str().unwrap().to_string(),
|
|
bin: entry.path.clone(),
|
|
// None source = None repo
|
|
repo: source.as_ref().map(|s|
|
|
Repo::new(dvcs, s, &dest, subupdates)
|
|
),
|
|
source,
|
|
config: HashMap::new(),
|
|
branch: entry.read_setting("checkout"),
|
|
hosts: entry.read_setting("hosts").map_or(Vec::new(), |c| c.split("\n").map(|line| line.to_string()).collect()),
|
|
cloned,
|
|
subupdates: entry.read_setting("subupdates").is_some(),
|
|
|
|
}
|
|
}
|
|
|
|
pub fn checkout(&self) {
|
|
if let Some(branch) = &self.branch {
|
|
println!("requesting branch");
|
|
if let Some(repo) = &self.repo {
|
|
println!("has repo");
|
|
repo.checkout(branch);
|
|
}
|
|
} else {
|
|
println!("no ranch requested");
|
|
}
|
|
}
|
|
|
|
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 update_and_run(&self, force: &bool) {
|
|
let mut context = HashMap::new();
|
|
context.insert("$i18n_task", self.name.as_str());
|
|
|
|
if let Some(repo) = &self.repo {
|
|
if repo.has_updates() {
|
|
self.run();
|
|
} else if *force {
|
|
log::debug("forcing", Some(&context));
|
|
self.run();
|
|
} else {
|
|
log::debug("no_update", Some(&context));
|
|
}
|
|
} else {
|
|
unreachable!("this function should never be called on a task whcih doesnt have a repo");
|
|
}
|
|
}
|
|
|
|
pub fn run(&self) {
|
|
if !self.run_on_host() { return; }
|
|
|
|
let cmd_out = Command::new("bash") // TODO: no need to call 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 list of Tasks
|
|
pub fn from_entries(db: Vec<Entry>) -> Vec<Task> {
|
|
db.iter().map(|x| Task::from_entry(&x)).collect()
|
|
}
|
|
|
|
/// Returns a list of tasks, or std::io::Error
|
|
/// Reads all entries in a directory
|
|
pub fn from_dir(base_dir: &str) -> Result<Vec<Task>, std::io::Error> {
|
|
Ok(from_entries(
|
|
db::from(base_dir, is_executable)?
|
|
))
|
|
}
|
|
|
|
/// Returns a list 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<Vec<Task>, db::Error> {
|
|
let mut tasks = Vec::new();
|
|
for task in list {
|
|
if let Some(entry) = db::entry(&basedir, is_executable, &task) {
|
|
tasks.push(Task::from_entry(&entry));
|
|
} else {
|
|
return Err(db::Error::EntryNotFound(task.clone()));
|
|
}
|
|
}
|
|
Ok(tasks)
|
|
}
|