Load tasks from URLs

This commit is contained in:
southerntofu 2020-11-28 15:03:04 +01:00
parent 70f476dcc9
commit bd6e1d67f9
1 changed files with 57 additions and 4 deletions

View File

@ -2,7 +2,7 @@ use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::process::Command;
use crate::db::{is_executable, read_extension};
use crate::db::{is_executable, read_extension, read_or_none};
use crate::dvcs::{Backend, Repo};
use crate::log;
@ -177,16 +177,69 @@ pub fn from_dir(basedir: &Path) -> Result<Vec<Task>, std::io::Error> {
pub struct MissingTask(pub String);
/// Contains a mapping of sources to their corresponding tasks
pub struct SourceSet {
mapping: HashMap<String, Vec<String>>,
}
impl SourceSet {
/// Loads a SourceSet from a basedir
pub fn from(basedir: &Path) -> Result<SourceSet, std::io::Error> {
let source_urls = basedir.read_dir()?.filter_map(|p| {
if p.is_err() { return None; } // Skip individual errors
let p = p.unwrap().path();
let path_str = p.to_str().unwrap();
if !path_str.ends_with(".source") {
// Filter out non-source files
return None;
}
return Some((
path_str.trim_end_matches(".source").to_string(), // Task name
read_or_none(&p).unwrap() // Source URL
));
});
let mut sources_map: HashMap<String, Vec<String>> = HashMap::new();
for (task, source) in source_urls {
if let Some(list) = sources_map.get_mut(&source) {
list.push(task.to_string());
} else {
sources_map.insert(source.clone(), vec!(task.to_string()));
}
}
Ok(SourceSet {
mapping: sources_map
})
}
/// Returns the task names associated with a given source
pub fn tasks_for(&self, source: &str) -> Option<Vec<String>> {
self.mapping.get(source).map(|x| x.clone())
}
}
/// Loads a task list from a given base directory, taking only tasks that are in requested list.
/// Fails if the directory is not readable with std::io::Error, or if a requested task does
/// not exist.
/// Given tasks can be either a task name or a task URL. This function will panic if the basedir
/// does not exist, or error if a requested task/source does not exist.
pub fn from_dir_and_list(basedir: &Path, list: Vec<String>) -> Result<Vec<Task>, MissingTask> {
// Safe unwrap because we checked that basedir existed before
// or maybe can crash for permission problem? TODO: write tests
let sourceset = SourceSet::from(basedir).unwrap();
let mut tasks = Vec::new();
for t in list {
if let Some(task) = Task::from_path(&basedir.join(&t)) {
tasks.push(task);
} else {
return Err(MissingTask(t));
// Maybe it's not a task name, but a task URL?
if let Some(list) = sourceset.tasks_for(&t) {
// Hopefully safe unwrap (unless there's a source without a corresponding task?)
let task_list = list.iter().map(|t_name| Task::from_path(&basedir.join(&t_name)).unwrap());
tasks.extend(task_list);
} else {
return Err(MissingTask(t));
}
}
}
Ok(tasks)