Adds support for ignore
This commit is contained in:
parent
8be3cb4a88
commit
5797a9a80b
98
src/lib.rs
98
src/lib.rs
|
@ -1,17 +1,17 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
use std::{io, thread, fmt};
|
|
||||||
use std::env::current_dir;
|
use std::env::current_dir;
|
||||||
use std::process::{Command, ExitStatus};
|
use std::fs::{create_dir_all, File};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::fs::{File, create_dir_all};
|
use std::process::{Command, ExitStatus};
|
||||||
use std::sync::mpsc::channel;
|
use std::sync::mpsc::channel;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use std::{fmt, io, thread};
|
||||||
|
|
||||||
use colored::*;
|
use colored::*;
|
||||||
|
|
||||||
use notify::{Watcher, RecursiveMode, watcher, DebouncedEvent};
|
use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
|
||||||
|
|
||||||
use notify_rust::{Notification, NotificationHandle};
|
use notify_rust::{Notification, NotificationHandle};
|
||||||
|
|
||||||
|
@ -39,7 +39,11 @@ impl fmt::Display for Error {
|
||||||
match self {
|
match self {
|
||||||
Error::NoBuilderFound => write!(fmt, "no builder found"),
|
Error::NoBuilderFound => write!(fmt, "no builder found"),
|
||||||
Error::IoError(e) => write!(fmt, "i/o error occured: {}", e),
|
Error::IoError(e) => write!(fmt, "i/o error occured: {}", e),
|
||||||
Error::CommandError(command, _, status) => write!(fmt, "command {} exited with status code {}", command, status),
|
Error::CommandError(command, _, status) => write!(
|
||||||
|
fmt,
|
||||||
|
"command {} exited with status code {}",
|
||||||
|
command, status
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,11 +62,7 @@ pub fn run_command(command: &str, path: &str) -> Result<(), Error> {
|
||||||
|
|
||||||
/// Run a build commands, and wait untils its finished, returning its result.
|
/// Run a build commands, and wait untils its finished, returning its result.
|
||||||
pub fn run_command_with_args(command: &str, path: &str, args: &Vec<String>) -> Result<(), Error> {
|
pub fn run_command_with_args(command: &str, path: &str, args: &Vec<String>) -> Result<(), Error> {
|
||||||
|
let mut child = Command::new(command).current_dir(path).args(args).spawn()?;
|
||||||
let mut child = Command::new(command)
|
|
||||||
.current_dir(path)
|
|
||||||
.args(args)
|
|
||||||
.spawn()?;
|
|
||||||
|
|
||||||
let exit = child.wait()?;
|
let exit = child.wait()?;
|
||||||
|
|
||||||
|
@ -74,29 +74,28 @@ pub fn run_command_with_args(command: &str, path: &str, args: &Vec<String>) -> R
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to build a certain directory using the specified builders.
|
/// Tries to build a certain directory using the specified builders.
|
||||||
pub fn build(path: &PathBuf, args: &Vec<String>, builders: &Vec<Box<Builder>>) -> Result<(), Error> {
|
pub fn build(
|
||||||
|
path: &PathBuf,
|
||||||
|
args: &Vec<String>,
|
||||||
|
builders: &Vec<Box<dyn Builder>>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
let mut path = path.clone();
|
let mut path = path.clone();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
|
||||||
if path.to_str().unwrap() == "/" {
|
if path.to_str().unwrap() == "/" {
|
||||||
// Couldn't find a buildable directory
|
// Couldn't find a buildable directory
|
||||||
return Err(Error::NoBuilderFound);
|
return Err(Error::NoBuilderFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
for builder in builders {
|
for builder in builders {
|
||||||
|
|
||||||
if builder.is_buildable(path.to_str().unwrap()) {
|
if builder.is_buildable(path.to_str().unwrap()) {
|
||||||
builder.build(path.to_str().unwrap(), &args)?;
|
builder.build(path.to_str().unwrap(), &args)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
path.pop();
|
path.pop();
|
||||||
};
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Destucture a Result to return a Result<(), ()>
|
/// Destucture a Result to return a Result<(), ()>
|
||||||
|
@ -121,9 +120,13 @@ pub fn builder_arguments_from_string(uri: &str) -> (PathBuf, Vec<String>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Watches a directory and builds it when a modification occurs.
|
/// Watches a directory and builds it when a modification occurs.
|
||||||
pub fn watch<P: AsRef<Path>>(p: P) -> Result<(), Error> {
|
pub fn watch<P: AsRef<Path>>(p: P, ignore: Vec<String>) -> Result<(), Error> {
|
||||||
let mut path = current_dir()?;
|
let path = PathBuf::from(p.as_ref()).canonicalize()?;
|
||||||
path.push(p.as_ref());
|
|
||||||
|
let ignore = ignore
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| PathBuf::from(x).canonicalize())
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let mut builder = GeneralBuilder::new();
|
let mut builder = GeneralBuilder::new();
|
||||||
|
@ -134,7 +137,7 @@ pub fn watch<P: AsRef<Path>>(p: P) -> Result<(), Error> {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("couldn't watch directory {}: {}", path.display(), e);
|
warn!("couldn't watch directory {}: {}", path.display(), e);
|
||||||
return;
|
return;
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(e) = watcher.watch(&path, RecursiveMode::Recursive) {
|
if let Err(e) = watcher.watch(&path, RecursiveMode::Recursive) {
|
||||||
|
@ -146,11 +149,14 @@ pub fn watch<P: AsRef<Path>>(p: P) -> Result<(), Error> {
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match rx.recv() {
|
match rx.recv() {
|
||||||
Ok(DebouncedEvent::NoticeWrite(_)) |
|
Ok(DebouncedEvent::NoticeWrite(x))
|
||||||
Ok(DebouncedEvent::Write(_)) |
|
| Ok(DebouncedEvent::Write(x))
|
||||||
Ok(DebouncedEvent::Create(_)) |
|
| Ok(DebouncedEvent::Create(x))
|
||||||
Ok(DebouncedEvent::Rename(_, _)) |
|
| Ok(DebouncedEvent::Rename(_, x))
|
||||||
Ok(DebouncedEvent::Chmod(_)) => {
|
| Ok(DebouncedEvent::Chmod(x)) => {
|
||||||
|
if ignore.iter().any(|y| x.starts_with(y)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let start_string = format!("---- STARTING BUILD ---- from {}", path.display());
|
let start_string = format!("---- STARTING BUILD ---- from {}", path.display());
|
||||||
println!("{}", start_string.bold().green());
|
println!("{}", start_string.bold().green());
|
||||||
|
@ -158,13 +164,13 @@ pub fn watch<P: AsRef<Path>>(p: P) -> Result<(), Error> {
|
||||||
match builder.build(&path, &vec![]) {
|
match builder.build(&path, &vec![]) {
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
println!("{}", "--------- FAIL ---------".bold().red());
|
println!("{}", "--------- FAIL ---------".bold().red());
|
||||||
},
|
}
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
println!("{}", "----- SUCCESSFUL -----".bold().green());
|
println!("{}", "----- SUCCESSFUL -----".bold().green());
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
println!();
|
println!();
|
||||||
},
|
}
|
||||||
Err(e) => error!("watch error: {:?}", e),
|
Err(e) => error!("watch error: {:?}", e),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
@ -183,7 +189,7 @@ pub struct GeneralBuilder {
|
||||||
failure: PathBuf,
|
failure: PathBuf,
|
||||||
|
|
||||||
/// The builders contained.
|
/// The builders contained.
|
||||||
builders: Vec<Box<Builder>>,
|
builders: Vec<Box<dyn Builder>>,
|
||||||
|
|
||||||
/// The id of the notification to update a notification if possible.
|
/// The id of the notification to update a notification if possible.
|
||||||
notification_handle: Option<NotificationHandle>,
|
notification_handle: Option<NotificationHandle>,
|
||||||
|
@ -192,7 +198,6 @@ pub struct GeneralBuilder {
|
||||||
impl GeneralBuilder {
|
impl GeneralBuilder {
|
||||||
/// Creates a new general builder with the defaults builders.
|
/// Creates a new general builder with the defaults builders.
|
||||||
pub fn new() -> GeneralBuilder {
|
pub fn new() -> GeneralBuilder {
|
||||||
|
|
||||||
let mut config = PathBuf::from(dirs::config_dir().unwrap());
|
let mut config = PathBuf::from(dirs::config_dir().unwrap());
|
||||||
config.push("mars");
|
config.push("mars");
|
||||||
|
|
||||||
|
@ -202,8 +207,7 @@ impl GeneralBuilder {
|
||||||
let mut failure = config.clone();
|
let mut failure = config.clone();
|
||||||
failure.push("failure.png");
|
failure.push("failure.png");
|
||||||
|
|
||||||
if ! success.exists() || ! failure.exists() {
|
if !success.exists() || !failure.exists() {
|
||||||
|
|
||||||
create_dir_all(&config).unwrap();
|
create_dir_all(&config).unwrap();
|
||||||
|
|
||||||
const SUCCESS_BYTES: &[u8] = include_bytes!("../assets/success.png");
|
const SUCCESS_BYTES: &[u8] = include_bytes!("../assets/success.png");
|
||||||
|
@ -250,7 +254,6 @@ impl GeneralBuilder {
|
||||||
|
|
||||||
/// Sends a notification of a successful build.
|
/// Sends a notification of a successful build.
|
||||||
pub fn notify_success(&mut self) {
|
pub fn notify_success(&mut self) {
|
||||||
|
|
||||||
match self.notification_handle.as_mut() {
|
match self.notification_handle.as_mut() {
|
||||||
Some(handle) => {
|
Some(handle) => {
|
||||||
handle
|
handle
|
||||||
|
@ -260,7 +263,7 @@ impl GeneralBuilder {
|
||||||
.icon(self.success.to_str().unwrap());
|
.icon(self.success.to_str().unwrap());
|
||||||
|
|
||||||
handle.update();
|
handle.update();
|
||||||
},
|
}
|
||||||
|
|
||||||
None => {
|
None => {
|
||||||
let handle = Notification::new()
|
let handle = Notification::new()
|
||||||
|
@ -271,17 +274,14 @@ impl GeneralBuilder {
|
||||||
.show();
|
.show();
|
||||||
|
|
||||||
self.notification_handle = handle.ok();
|
self.notification_handle = handle.ok();
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = Notification::new()
|
let _ = Notification::new().show();
|
||||||
.show();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends a notification of an error.
|
/// Sends a notification of an error.
|
||||||
pub fn notify_error(&self, e: &Error) {
|
pub fn notify_error(&self, e: &Error) {
|
||||||
|
|
||||||
let body = match e {
|
let body = match e {
|
||||||
Error::NoBuilderFound => "No builder was found for this directory".to_string(),
|
Error::NoBuilderFound => "No builder was found for this directory".to_string(),
|
||||||
Error::IoError(ref e) => format!("Error while running command: {:?}", e).to_string(),
|
Error::IoError(ref e) => format!("Error while running command: {:?}", e).to_string(),
|
||||||
|
@ -291,9 +291,14 @@ impl GeneralBuilder {
|
||||||
Some(e) => e.to_string(),
|
Some(e) => e.to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
format!("Command \"{} {}\" failed: {}",
|
format!(
|
||||||
command, args.join(" "), status).to_string()
|
"Command \"{} {}\" failed: {}",
|
||||||
},
|
command,
|
||||||
|
args.join(" "),
|
||||||
|
status
|
||||||
|
)
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = Notification::new()
|
let _ = Notification::new()
|
||||||
|
@ -302,9 +307,7 @@ impl GeneralBuilder {
|
||||||
.body(&body)
|
.body(&body)
|
||||||
.icon(self.failure.to_str().unwrap())
|
.icon(self.failure.to_str().unwrap())
|
||||||
.show();
|
.show();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A generic builder. It can build some projects.
|
/// A generic builder. It can build some projects.
|
||||||
|
@ -354,13 +357,11 @@ impl Builder for CMakeBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build(&self, path: &str, args: &Vec<String>) -> Result<(), Error> {
|
fn build(&self, path: &str, args: &Vec<String>) -> Result<(), Error> {
|
||||||
|
|
||||||
let mut build = PathBuf::from(path);
|
let mut build = PathBuf::from(path);
|
||||||
build.push("build");
|
build.push("build");
|
||||||
|
|
||||||
// If there's a build/Makefile, we'll only make
|
// If there's a build/Makefile, we'll only make
|
||||||
if ! contains_file(path, "build/Makefile") {
|
if !contains_file(path, "build/Makefile") {
|
||||||
|
|
||||||
// Create build directory
|
// Create build directory
|
||||||
create_dir_all(&build)?;
|
create_dir_all(&build)?;
|
||||||
|
|
||||||
|
@ -372,7 +373,6 @@ impl Builder for CMakeBuilder {
|
||||||
run_command_with_args("make", build.to_str().unwrap(), args)?;
|
run_command_with_args("make", build.to_str().unwrap(), args)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The builder that looks for Cargo.toml.
|
/// The builder that looks for Cargo.toml.
|
||||||
|
|
|
@ -1,28 +1,86 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
use std::{thread, env};
|
use std::process::exit;
|
||||||
use std::sync::{Mutex, Arc, mpsc};
|
use std::sync::{mpsc, Arc, Mutex};
|
||||||
|
use std::{env, thread};
|
||||||
|
|
||||||
use colored::*;
|
use colored::*;
|
||||||
|
|
||||||
use percent_encoding::percent_decode;
|
use percent_encoding::percent_decode;
|
||||||
|
|
||||||
use hyper::{Body, Response, Server};
|
|
||||||
use hyper::service::service_fn_ok;
|
|
||||||
use hyper::rt::Future;
|
use hyper::rt::Future;
|
||||||
|
use hyper::service::service_fn_ok;
|
||||||
|
use hyper::{Body, Response, Server};
|
||||||
|
|
||||||
use mars::{GeneralBuilder, builder_arguments_from_string, watch};
|
use mars::{builder_arguments_from_string, watch, GeneralBuilder};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
||||||
beautylog::init(log::LevelFilter::Info).ok();
|
beautylog::init(log::LevelFilter::Info).ok();
|
||||||
|
|
||||||
let args = env::args().collect::<Vec<_>>();
|
let mut args = env::args()
|
||||||
|
.skip(1)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.into_iter()
|
||||||
|
.peekable();
|
||||||
|
|
||||||
if args.len() == 3 && args[1] == "-w" {
|
let mut watching = None;
|
||||||
if let Err(e) = watch(&args[2]) {
|
let mut ignore = vec![];
|
||||||
|
|
||||||
|
let exit_code = loop {
|
||||||
|
let arg = args.next();
|
||||||
|
let arg = arg.as_deref();
|
||||||
|
|
||||||
|
let next = args.peek();
|
||||||
|
let next = next.as_deref();
|
||||||
|
|
||||||
|
let watch_is_some = watching.is_some();
|
||||||
|
|
||||||
|
match (arg, next, watch_is_some) {
|
||||||
|
(None, _, _) => {
|
||||||
|
break None;
|
||||||
|
}
|
||||||
|
|
||||||
|
(Some("-w") | Some("--watch"), Some(value), false) => {
|
||||||
|
watching = Some(value.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
(Some("-w") | Some("--watch"), Some(_), true) => {
|
||||||
|
error!("argument watch present multiple times");
|
||||||
|
break Some(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
(Some("-w") | Some("--watch"), None, _) => {
|
||||||
|
error!("argument watch without value");
|
||||||
|
break Some(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
(Some("-i") | Some("--ignore"), Some(value), _) => {
|
||||||
|
ignore.push(value.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
(Some("-i") | Some("--ignore"), None, _) => {
|
||||||
|
error!("argument ignore without value");
|
||||||
|
break Some(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
(Some(value), _, _) => {
|
||||||
|
error!("argument \"{}\" unknown", value);
|
||||||
|
break Some(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
args.next();
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(exit_code) = exit_code {
|
||||||
|
exit(exit_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(watching) = watching {
|
||||||
|
if let Err(e) = watch(&watching, ignore) {
|
||||||
error!("{}", e);
|
error!("{}", e);
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +90,6 @@ fn main() {
|
||||||
let clone = tasks.clone();
|
let clone = tasks.clone();
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
|
|
||||||
let addr = ([127, 0, 0, 1], 1500).into();
|
let addr = ([127, 0, 0, 1], 1500).into();
|
||||||
|
|
||||||
let server = Server::bind(&addr)
|
let server = Server::bind(&addr)
|
||||||
|
@ -50,37 +107,37 @@ fn main() {
|
||||||
|
|
||||||
info!("mars server listening on {}...", addr);
|
info!("mars server listening on {}...", addr);
|
||||||
hyper::rt::run(server);
|
hyper::rt::run(server);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut builder = GeneralBuilder::new();
|
let mut builder = GeneralBuilder::new();
|
||||||
|
|
||||||
for _ in rx {
|
for _ in rx {
|
||||||
|
|
||||||
let uri = {
|
let uri = {
|
||||||
let mut tasks = tasks.lock().unwrap();
|
let mut tasks = tasks.lock().unwrap();
|
||||||
tasks.pop()
|
tasks.pop()
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(uri) = uri {
|
if let Some(uri) = uri {
|
||||||
|
|
||||||
let uri = percent_decode(uri.path().as_bytes()).decode_utf8().unwrap();
|
let uri = percent_decode(uri.path().as_bytes()).decode_utf8().unwrap();
|
||||||
let (path, args) = builder_arguments_from_string(&*uri);
|
let (path, args) = builder_arguments_from_string(&*uri);
|
||||||
|
|
||||||
let path_string = path.to_str().unwrap();
|
let path_string = path.to_str().unwrap();
|
||||||
let start_string = format!("---- STARTING BUILD ---- from {} {}", path_string, args.join(" "));
|
let start_string = format!(
|
||||||
|
"---- STARTING BUILD ---- from {} {}",
|
||||||
|
path_string,
|
||||||
|
args.join(" ")
|
||||||
|
);
|
||||||
println!("{}", start_string.bold().green());
|
println!("{}", start_string.bold().green());
|
||||||
|
|
||||||
match builder.build(&path, &args) {
|
match builder.build(&path, &args) {
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
println!("{}", "--------- FAIL ---------".bold().red());
|
println!("{}", "--------- FAIL ---------".bold().red());
|
||||||
},
|
}
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
println!("{}", "----- SUCCESSFUL -----".bold().green());
|
println!("{}", "----- SUCCESSFUL -----".bold().green());
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
println!();
|
println!();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue