DB is not specific to tasks
This commit is contained in:
parent
65ab08a75c
commit
01b832f614
170
src/db.rs
170
src/db.rs
|
@ -1,154 +1,67 @@
|
||||||
use std::path::{PathBuf, Path};
|
use std::path::{PathBuf,Path};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::os::unix::fs::MetadataExt;
|
use std::os::unix::fs::MetadataExt;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
//use crate::log;
|
|
||||||
use crate::dvcs;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum DbError {
|
pub enum DbError {
|
||||||
TaskNotFound(String)
|
EntryNotFound(String)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Entry {
|
pub struct Entry {
|
||||||
base_dir: PathBuf,
|
|
||||||
pub name: OsString
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Task {
|
|
||||||
pub name: OsString,
|
pub name: OsString,
|
||||||
pub bin: PathBuf,
|
pub path: PathBuf,
|
||||||
pub source: Option<String>,
|
pub base_dir: PathBuf,
|
||||||
pub dvcs: dvcs::Backend,
|
|
||||||
pub config: HashMap<String, String>,
|
|
||||||
pub branch: Option<String>,
|
|
||||||
pub host: Option<String>,
|
|
||||||
pub cloned: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Task {
|
|
||||||
pub fn new(base_dir: PathBuf, name: OsString) -> Task {
|
|
||||||
let t = Entry::new(base_dir, name.clone());
|
|
||||||
let source = t.source();
|
|
||||||
let cloned = source.clone().map_or(false, |_| {
|
|
||||||
let mut path = t.base_dir.clone();
|
|
||||||
path.push(format!(".{}", t.name.to_str().expect("WTF")));
|
|
||||||
path.is_dir()
|
|
||||||
});
|
|
||||||
Task {
|
|
||||||
name: name.clone(),
|
|
||||||
bin: PathBuf::from(name.clone()),
|
|
||||||
source,
|
|
||||||
dvcs: dvcs::from_setting(t.dvcs()),
|
|
||||||
config: HashMap::new(),
|
|
||||||
branch: t.branch(),
|
|
||||||
host: t.host(),
|
|
||||||
cloned,
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Entry {
|
impl Entry {
|
||||||
pub fn new(base_dir: PathBuf, name: OsString) -> Entry {
|
pub fn new(path: PathBuf, name: OsString, base_dir: PathBuf) -> Entry {
|
||||||
Entry {
|
Entry {
|
||||||
|
path,
|
||||||
|
name,
|
||||||
base_dir,
|
base_dir,
|
||||||
name
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_setting(&self, setting: &str) -> Option<String> {
|
pub fn read_setting(&self, setting: &str) -> Option<String> {
|
||||||
let mut path = self.base_dir.clone();
|
let mut path = self.path.clone();
|
||||||
path.push(&self.name);
|
|
||||||
path.set_extension(setting);
|
path.set_extension(setting);
|
||||||
read_or_none(&path)
|
read_or_none(&path)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn source(&self) -> Option<String> {
|
|
||||||
self.read_setting("source")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dvcs(&self) -> Option<String> {
|
|
||||||
self.read_setting("dvcs")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn branch(&self) -> Option<String> {
|
|
||||||
self.read_setting("branch")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn host(&self) -> Option<String> {
|
|
||||||
self.read_setting("branch")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Database {
|
pub fn from(path_name: &str, filter: impl Fn(&Path) -> bool) -> Result<Vec<Entry>, std::io::Error> {
|
||||||
base_dir: PathBuf
|
let path = PathBuf::from(&path_name);
|
||||||
|
|
||||||
|
let mut entries = Vec::new();
|
||||||
|
|
||||||
|
for file in path.read_dir()? {
|
||||||
|
if file.is_err() {
|
||||||
|
// Dismiss individual errors (in case there's a permission problem)
|
||||||
|
// TODO: maybe print a warning? Actually a configurable error level
|
||||||
|
// (using enum variants) should be passed to the function to configure
|
||||||
|
// whether to continue silently or error out for individual files
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let entry = file?.path();
|
||||||
|
if filter(&entry) {
|
||||||
|
entries.push(
|
||||||
|
Entry::new(
|
||||||
|
entry.clone(),
|
||||||
|
entry.file_name().expect("Failed to read file name").to_os_string(),
|
||||||
|
path.clone()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Database {
|
/// Reads the file and strips whitespace (including newlines)
|
||||||
pub fn from_folder(p: &str) -> Database {
|
|
||||||
let path = PathBuf::from(&p);
|
|
||||||
if !path.is_dir() {
|
|
||||||
panic!("Folder {} not found", &p);
|
|
||||||
}
|
|
||||||
Database {
|
|
||||||
base_dir: path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tasks(&self) -> Vec<Task> {
|
|
||||||
// If database doesn't exist, simply return an empty vec
|
|
||||||
let mut res = Vec::new();
|
|
||||||
for file in list_files(&self.base_dir) {
|
|
||||||
if is_executable(&file) {
|
|
||||||
res.push(
|
|
||||||
Task::new(self.base_dir.clone(), file.file_name().expect("WTF").to_os_string())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This one works with a list of tasks passed as argument
|
|
||||||
// It fails when a task wasn't found, instead of continuing silently
|
|
||||||
pub fn tasks_from(&self, list: Vec<String>) -> Result<Vec<Task>, DbError> {
|
|
||||||
let mut res = Vec::new();
|
|
||||||
for entry in &list {
|
|
||||||
let mut path = self.base_dir.clone();
|
|
||||||
path.push(entry);
|
|
||||||
if !path.is_file() {
|
|
||||||
return Err(DbError::TaskNotFound(entry.to_string()));
|
|
||||||
}
|
|
||||||
if is_executable(&path) {
|
|
||||||
res.push(Task::new(self.base_dir.clone(), path.file_name().expect("WTF").to_os_string()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Ok(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn task(&self, name: &str) -> Option<Task> {
|
|
||||||
let mut path = self.base_dir.clone();
|
|
||||||
path.push(name);
|
|
||||||
if !path.is_file() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(
|
|
||||||
Task::new(self.base_dir.clone(), path.file_name().expect("WTF").to_os_string())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reads the file and strips whitespace (newline including)
|
|
||||||
/// Useful for file-based key-value store
|
/// Useful for file-based key-value store
|
||||||
fn read_or_none(path: &Path) -> Option<String> {
|
pub fn read_or_none(path: &Path) -> Option<String> {
|
||||||
if !path.is_file() {
|
if !path.is_file() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -162,7 +75,6 @@ fn read_or_none(path: &Path) -> Option<String> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_files(path: &Path) -> Vec<PathBuf> {
|
fn list_files(path: &Path) -> Vec<PathBuf> {
|
||||||
|
@ -192,7 +104,11 @@ fn list_files(path: &Path) -> Vec<PathBuf> {
|
||||||
|
|
||||||
|
|
||||||
// If the file doesn't exist or fails, return false
|
// If the file doesn't exist or fails, return false
|
||||||
fn is_executable(path: &Path) -> bool {
|
pub fn is_executable(path: &Path) -> bool {
|
||||||
|
// Do not match directories
|
||||||
|
if !path.is_file() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
match fs::metadata(path) {
|
match fs::metadata(path) {
|
||||||
Ok(stat) => {
|
Ok(stat) => {
|
||||||
let mode = stat.mode();
|
let mode = stat.mode();
|
||||||
|
|
16
src/main.rs
16
src/main.rs
|
@ -1,30 +1,35 @@
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
// For UNIX extended metadata
|
||||||
|
|
||||||
mod log;
|
mod log;
|
||||||
mod db;
|
mod db;
|
||||||
mod dvcs;
|
mod dvcs;
|
||||||
mod cli;
|
mod cli;
|
||||||
|
mod task;
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), std::io::Error> {
|
||||||
|
|
||||||
let home_dir = env::var("HOME").expect("$HOME not defined. WTF?");
|
let home_dir = env::var("HOME").expect("$HOME not defined. WTF?");
|
||||||
let base_dir = format!("{}/.git-build", home_dir);
|
let base_dir = format!("{}/.git-build", home_dir);
|
||||||
|
|
||||||
let db = db::Database::from_folder(&base_dir);
|
//let entries = db::Database::from(&base_dir, is_executable)?;
|
||||||
|
let tasks = task::from_dir(&base_dir).expect("Could not load DB");
|
||||||
|
|
||||||
let cmd = cli::Cli::from_args();
|
let cmd = cli::Cli::from_args();
|
||||||
|
|
||||||
|
/*
|
||||||
let tasks = if cmd.tasks.is_empty() {
|
let tasks = if cmd.tasks.is_empty() {
|
||||||
db.tasks()
|
db.tasks()
|
||||||
} else {
|
} else {
|
||||||
db.tasks_from(cmd.tasks).expect("Could not process the lsit of tasks given")
|
db.tasks_from(cmd.tasks).expect("Could not process the lsit of tasks given")
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
for task in tasks {
|
for (task_name, task) in tasks.iter() {
|
||||||
let mut context = HashMap::new();
|
let mut context = HashMap::new();
|
||||||
context.insert("$i18n_task", task.name.to_str().expect("WTF"));
|
//context.insert("$i18n_task", task_name.to_str().expect("WTF"));
|
||||||
|
context.insert("$i18n_task", task_name.as_str());
|
||||||
log::debug("found_task", Some(&context));
|
log::debug("found_task", Some(&context));
|
||||||
if task.cloned == false {
|
if task.cloned == false {
|
||||||
// Maybe the task has a source we should clone?
|
// Maybe the task has a source we should clone?
|
||||||
|
@ -42,4 +47,5 @@ fn main() {
|
||||||
}
|
}
|
||||||
// So the cloned repo is here maybe update?
|
// So the cloned repo is here maybe update?
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::ffi::OsString;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
//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 host: Option<String>,
|
||||||
|
pub cloned: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
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"),
|
||||||
|
host: entry.read_setting("host"),
|
||||||
|
cloned,
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_dir(base_dir: &str) -> Result<HashMap<String, Task>, std::io::Error> {
|
||||||
|
Ok(from_entries(
|
||||||
|
db::from(base_dir, is_executable)?
|
||||||
|
))
|
||||||
|
}
|
Loading…
Reference in New Issue