From bd6e1d67f92c94c9a0cb309ccb539ce4e335d856 Mon Sep 17 00:00:00 2001 From: southerntofu Date: Sat, 28 Nov 2020 15:03:04 +0100 Subject: [PATCH] Load tasks from URLs --- src/task.rs | 61 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/src/task.rs b/src/task.rs index 00e5978..ba7fe29 100644 --- a/src/task.rs +++ b/src/task.rs @@ -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, std::io::Error> { pub struct MissingTask(pub String); +/// Contains a mapping of sources to their corresponding tasks +pub struct SourceSet { + mapping: HashMap>, +} + +impl SourceSet { + + /// Loads a SourceSet from a basedir + pub fn from(basedir: &Path) -> Result { + 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> = 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> { + 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) -> Result, 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)