Reorder tasks, start implementing git
This commit is contained in:
parent
5bee567e34
commit
19e9b98302
104
src/dvcs.rs
104
src/dvcs.rs
|
@ -1,4 +1,5 @@
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
use std::path::{Path,PathBuf};
|
||||||
|
|
||||||
pub fn from_setting(setting: Option<String>) -> Backend {
|
pub fn from_setting(setting: Option<String>) -> Backend {
|
||||||
// Git is the default setting until further notice
|
// Git is the default setting until further notice
|
||||||
|
@ -16,15 +17,54 @@ pub enum Backend {
|
||||||
Unknown(String),
|
Unknown(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Backend {
|
#[derive(Debug)]
|
||||||
pub fn clone(&self, source: &str, dest: &str) -> bool {
|
pub struct Repo {
|
||||||
match self {
|
pub backend: Backend,
|
||||||
|
pub source: String,
|
||||||
|
pub dest: PathBuf,
|
||||||
|
pub subupdates: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Repo {
|
||||||
|
pub fn new(backend: Backend, source: &str, dest: &Path, subupdates: bool) -> Repo {
|
||||||
|
Repo {
|
||||||
|
backend,
|
||||||
|
source: source.to_string(),
|
||||||
|
dest: dest.to_path_buf(),
|
||||||
|
subupdates
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn branch(&self) -> String {
|
||||||
|
match &self.backend {
|
||||||
|
Backend::Git => {
|
||||||
|
let output = Command::new("git")
|
||||||
|
.arg("rev-parse")
|
||||||
|
.arg("--abbrev-ref")
|
||||||
|
.arg("HEAD")
|
||||||
|
.output().expect("WTF");
|
||||||
|
if !output.status.success() {
|
||||||
|
panic!("Corrupted git repository???");
|
||||||
|
}
|
||||||
|
String::from_utf8(output.stdout).unwrap().trim().to_string()
|
||||||
|
},
|
||||||
|
Backend::Mercurial => {
|
||||||
|
unreachable!("UNIMPLEMENTED!");
|
||||||
|
},
|
||||||
|
Backend::Unknown(name) => {
|
||||||
|
panic!("Uknown backend: {}. Cannot find ranch", name);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clone(&self) -> bool {
|
||||||
|
match &self.backend {
|
||||||
Backend::Git => {
|
Backend::Git => {
|
||||||
let status = Command::new("git")
|
let status = Command::new("git")
|
||||||
.arg("clone")
|
.arg("clone")
|
||||||
.arg("--recursive")
|
.arg("--recursive")
|
||||||
.arg(source)
|
.arg(&self.source)
|
||||||
.arg(dest)
|
.arg(&self.dest)
|
||||||
.status().expect("PROCESS ERROR!");
|
.status().expect("PROCESS ERROR!");
|
||||||
status.success()
|
status.success()
|
||||||
},
|
},
|
||||||
|
@ -38,6 +78,60 @@ impl Backend {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn checkout(&self, target: &str) -> bool {
|
||||||
|
println!("CHECKOUT TO {}", target);
|
||||||
|
match &self.backend {
|
||||||
|
Backend::Git => {
|
||||||
|
let status = Command::new("git")
|
||||||
|
.arg("checkout")
|
||||||
|
.arg(target)
|
||||||
|
.status().expect("PROCESS ERROR!");
|
||||||
|
status.success()
|
||||||
|
},
|
||||||
|
Backend::Mercurial => {
|
||||||
|
unreachable!("UNIMPLEMENTED");
|
||||||
|
},
|
||||||
|
Backend::Unknown(name) => {
|
||||||
|
eprintln!("Unknown DVCS: {}", name);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_updates(&self) -> bool {
|
||||||
|
match &self.backend {
|
||||||
|
Backend::Git => {
|
||||||
|
// Refresh remote
|
||||||
|
if !Command::new("git")
|
||||||
|
.arg("fetch")
|
||||||
|
.arg("--quiet")
|
||||||
|
.arg("origin")
|
||||||
|
.status().expect("WTF").success() {
|
||||||
|
// FAILED, no internet??
|
||||||
|
eprintln!("Fetching updates failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let branch = self.branch();
|
||||||
|
if Command::new("git")
|
||||||
|
.arg("diff")
|
||||||
|
.arg("--quiet")
|
||||||
|
.arg(format!("remotes/origin/{}", &branch))
|
||||||
|
.status().expect("WTF").success() {
|
||||||
|
// Command succeeeded, no updates
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Updates
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
Backend::Mercurial => {
|
||||||
|
unreachable!("unimplemented");
|
||||||
|
},
|
||||||
|
Backend::Unknown(name) => {
|
||||||
|
eprintln!("Unknown DVCS:{}!", name);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
/// Runs an update on the repository in dest. Returns true
|
/// Runs an update on the repository in dest. Returns true
|
||||||
/// when an update was performed, false otherwise
|
/// when an update was performed, false otherwise
|
||||||
|
|
43
src/main.rs
43
src/main.rs
|
@ -15,7 +15,7 @@ fn main() -> Result<(), std::io::Error> {
|
||||||
|
|
||||||
std::env::set_var("GITBUILDDIR", &base_dir);
|
std::env::set_var("GITBUILDDIR", &base_dir);
|
||||||
|
|
||||||
let tasks = if cmd.tasks.is_empty() {
|
let mut tasks = if cmd.tasks.is_empty() {
|
||||||
task::from_dir(&base_dir).expect("Could not load DB")
|
task::from_dir(&base_dir).expect("Could not load DB")
|
||||||
} else {
|
} else {
|
||||||
task::from_dir_and_list(&base_dir, cmd.tasks).expect("Could not load given tasks")
|
task::from_dir_and_list(&base_dir, cmd.tasks).expect("Could not load given tasks")
|
||||||
|
@ -25,41 +25,52 @@ fn main() -> Result<(), std::io::Error> {
|
||||||
|
|
||||||
std::env::set_var("GITBUILDCONF", &config_folder);
|
std::env::set_var("GITBUILDCONF", &config_folder);
|
||||||
|
|
||||||
for (task_name, task) in tasks.iter() {
|
// Reorder tasks alphanumerically
|
||||||
if ignored_tasks.contains(&task_name) {
|
tasks.sort_unstable_by_key(|t| t.name.clone());
|
||||||
|
// Remove duplicates, in case a task was called along
|
||||||
|
// the corresponding source URL (so we'd be tempted to call the task twice)
|
||||||
|
tasks.dedup_by_key(|t| t.name.clone());
|
||||||
|
for task in &tasks {
|
||||||
|
if ignored_tasks.contains(&task.name) {
|
||||||
// Skip task which has CONFIG/task.ignore
|
// Skip task which has CONFIG/task.ignore
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
println!("TASK: {:?}", task_name);
|
println!("TASK: {:?}", task.name);
|
||||||
|
|
||||||
let mut context = HashMap::new();
|
let mut context = HashMap::new();
|
||||||
context.insert("$i18n_task", task_name.as_str());
|
context.insert("$i18n_task", task.name.as_str());
|
||||||
log::debug("found_task", Some(&context));
|
log::debug("found_task", Some(&context));
|
||||||
// Maybe the task has a source we should clone?
|
// Maybe the task has a source we should clone?
|
||||||
if let Some(source) = &task.source {
|
if let Some(repo) = &task.repo {
|
||||||
let source_dir = format!("{}/.{}", base_dir, task_name.as_str());
|
let source_dir = format!("{}/.{}", base_dir, &task.name);
|
||||||
if task.cloned == false {
|
if task.cloned == false {
|
||||||
if !task.dvcs.clone(source, &source_dir) {
|
if !repo.clone() {
|
||||||
context.insert("$i18n_source", &source);
|
context.insert("$i18n_source", &repo.source);
|
||||||
log::error("clone_failed", Some(&context));
|
log::error("clone_failed", Some(&context));
|
||||||
// Skip further processing
|
// Skip further processing
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// New repo just cloned
|
// New repo just cloned
|
||||||
// TODO: submodule and submodule updates
|
// TODO: submodule and submodule updates
|
||||||
println!("Downloaded source for {}", task_name);
|
println!("Downloaded source for {}", task.name);
|
||||||
std::env::set_current_dir(&source_dir);
|
std::env::set_current_dir(&source_dir);
|
||||||
|
|
||||||
|
// Checkout specific branch?
|
||||||
|
task.checkout();
|
||||||
task.run();
|
task.run();
|
||||||
|
} else {
|
||||||
|
// So the cloned repo is already here maybe update?
|
||||||
|
// Let's say there was an update and run
|
||||||
|
println!("Task {} already exists, run i t only if updates", task.name);
|
||||||
|
std::env::set_current_dir(&source_dir);
|
||||||
|
task.checkout();
|
||||||
|
task.update_and_run(&cmd.force);
|
||||||
|
//task.run();
|
||||||
}
|
}
|
||||||
// So the cloned repo is already here maybe update?
|
|
||||||
// Let's say there was an update and run
|
|
||||||
println!("Task {} already exists, run it", task_name);
|
|
||||||
std::env::set_current_dir(&source_dir);
|
|
||||||
task.run();
|
|
||||||
} else {
|
} else {
|
||||||
// No source, chaneg working dir to basedir
|
// No source, chaneg working dir to basedir
|
||||||
std::env::set_current_dir(&base_dir);
|
std::env::set_current_dir(&base_dir);
|
||||||
println!("Taks {} doesn't have a source, run it", task_name);
|
println!("Taks {} doesn't have a source, run it", task.name);
|
||||||
task.run_once();
|
task.run_once();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
99
src/task.rs
99
src/task.rs
|
@ -1,23 +1,24 @@
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::ffi::OsString;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
//use crate::log;
|
|
||||||
use crate::dvcs;
|
use crate::dvcs;
|
||||||
|
use crate::dvcs::{Backend,Repo};
|
||||||
use crate::db;
|
use crate::db;
|
||||||
use crate::db::{Entry,is_executable};
|
use crate::db::{Entry,is_executable};
|
||||||
|
use crate::log;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Task {
|
pub struct Task {
|
||||||
pub name: OsString,
|
pub name: String,
|
||||||
pub bin: PathBuf,
|
pub bin: PathBuf,
|
||||||
pub source: Option<String>,
|
pub source: Option<String>,
|
||||||
pub dvcs: dvcs::Backend,
|
pub repo: Option<Repo>,
|
||||||
pub config: HashMap<String, String>,
|
pub config: HashMap<String, String>,
|
||||||
pub branch: Option<String>,
|
pub branch: Option<String>,
|
||||||
pub hosts: Vec<String>,
|
pub hosts: Vec<String>,
|
||||||
pub cloned: bool,
|
pub cloned: bool,
|
||||||
|
pub subupdates: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// config returns an option of (settings directory, ignored tasks) as
|
/// config returns an option of (settings directory, ignored tasks) as
|
||||||
|
@ -30,7 +31,7 @@ pub fn config(basedir: &Path) -> (PathBuf, Vec<String>) {
|
||||||
if path.is_dir() {
|
if path.is_dir() {
|
||||||
let ignored = path.read_dir().unwrap().filter_map(|x| {
|
let ignored = path.read_dir().unwrap().filter_map(|x| {
|
||||||
if x.is_err() { return None; }
|
if x.is_err() { return None; }
|
||||||
let mut name = x.unwrap().file_name().into_string().unwrap();
|
let name = x.unwrap().file_name().into_string().unwrap();
|
||||||
if name.ends_with(".ignore") {
|
if name.ends_with(".ignore") {
|
||||||
return Some(name.trim_end_matches(".ignore").to_string());
|
return Some(name.trim_end_matches(".ignore").to_string());
|
||||||
}
|
}
|
||||||
|
@ -46,24 +47,42 @@ pub fn config(basedir: &Path) -> (PathBuf, Vec<String>) {
|
||||||
impl Task {
|
impl Task {
|
||||||
pub fn from_entry(entry: &Entry) -> Task {
|
pub fn from_entry(entry: &Entry) -> Task {
|
||||||
let source = entry.read_setting("source");
|
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, |_| {
|
let cloned = source.clone().map_or(false, |_| {
|
||||||
let mut path = entry.base_dir.clone();
|
dest.is_dir()
|
||||||
path.push(format!(".{}", entry.name.to_str().expect("WTF")));
|
|
||||||
path.is_dir()
|
|
||||||
});
|
});
|
||||||
|
let subupdates = entry.read_setting("subupdates").is_some();
|
||||||
|
let dvcs = dvcs::from_setting(entry.read_setting("dvcs"));
|
||||||
|
|
||||||
Task {
|
Task {
|
||||||
name: entry.name.clone(),
|
name: entry.name.to_str().unwrap().to_string(),
|
||||||
bin: entry.path.clone(),
|
bin: entry.path.clone(),
|
||||||
|
// None source = None repo
|
||||||
|
repo: source.as_ref().map(|s|
|
||||||
|
Repo::new(dvcs, s, &dest, subupdates)
|
||||||
|
),
|
||||||
source,
|
source,
|
||||||
dvcs: dvcs::from_setting(entry.read_setting("dvcs")),
|
|
||||||
config: HashMap::new(),
|
config: HashMap::new(),
|
||||||
branch: entry.read_setting("branch"),
|
branch: entry.read_setting("checkout"),
|
||||||
hosts: entry.read_setting("hosts").map_or(Vec::new(), |c| c.split("\n").map(|line| line.to_string()).collect()),
|
hosts: entry.read_setting("hosts").map_or(Vec::new(), |c| c.split("\n").map(|line| line.to_string()).collect()),
|
||||||
cloned,
|
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 {
|
pub fn run_on_host(&self) -> bool {
|
||||||
println!("{:#?}", self.hosts);
|
println!("{:#?}", self.hosts);
|
||||||
if self.hosts.len() == 0 {
|
if self.hosts.len() == 0 {
|
||||||
|
@ -81,9 +100,28 @@ impl Task {
|
||||||
return false;
|
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) {
|
pub fn run(&self) {
|
||||||
if !self.run_on_host() { return; }
|
if !self.run_on_host() { return; }
|
||||||
let cmd_out = Command::new("bash")
|
|
||||||
|
let cmd_out = Command::new("bash") // TODO: no need to call bash?
|
||||||
.arg(&self.bin)
|
.arg(&self.bin)
|
||||||
.arg(&self.name)
|
.arg(&self.name)
|
||||||
.output()
|
.output()
|
||||||
|
@ -105,41 +143,30 @@ impl Task {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Takes an already instanced database (ie Vec<Entry>)
|
// Takes an already instanced database (ie Vec<Entry>)
|
||||||
// to turn into a dictionary of Tasks
|
// to turn into a list of Tasks
|
||||||
pub fn from_entries(db: Vec<Entry>) -> HashMap<String, Task> {
|
pub fn from_entries(db: Vec<Entry>) -> Vec<Task> {
|
||||||
let mut res: HashMap<String, Task> = HashMap::new();
|
db.iter().map(|x| Task::from_entry(&x)).collect()
|
||||||
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
|
/// Returns a list of tasks, or std::io::Error
|
||||||
/// Reads all entries in a directory
|
/// Reads all entries in a directory
|
||||||
pub fn from_dir(base_dir: &str) -> Result<HashMap<String, Task>, std::io::Error> {
|
pub fn from_dir(base_dir: &str) -> Result<Vec<Task>, std::io::Error> {
|
||||||
Ok(from_entries(
|
Ok(from_entries(
|
||||||
db::from(base_dir, is_executable)?
|
db::from(base_dir, is_executable)?
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a hashmap of tasks, or std::io::Error
|
/// 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
|
/// Reads entries in a given list from a directory, fails if a requested entry doesn't exist
|
||||||
/// (does not load the whole folder)
|
/// (does not load the whole folder)
|
||||||
pub fn from_dir_and_list(basedir: &str, list: Vec<String>) -> Result<HashMap<String, Task>, db::Error> {
|
pub fn from_dir_and_list(basedir: &str, list: Vec<String>) -> Result<Vec<Task>, db::Error> {
|
||||||
let mut entries: HashMap<String, Task> = HashMap::new();
|
let mut tasks = Vec::new();
|
||||||
for item in list {
|
for task in list {
|
||||||
if let Some(entry) = db::entry(&basedir, is_executable, &item) {
|
if let Some(entry) = db::entry(&basedir, is_executable, &task) {
|
||||||
entries.insert(item.clone(), Task::from_entry(&entry));
|
tasks.push(Task::from_entry(&entry));
|
||||||
} else {
|
} else {
|
||||||
return Err(db::Error::EntryNotFound(item.clone()))
|
return Err(db::Error::EntryNotFound(task.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(tasks)
|
||||||
Ok(
|
|
||||||
entries
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue