Actually run recipes, add a bunch of tests
This commit is contained in:
parent
063deb43c4
commit
355fd685ba
19
Cargo.lock
generated
19
Cargo.lock
generated
@ -4,6 +4,7 @@ version = "0.1.5"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 2.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 0.1.77 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 0.1.77 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -61,6 +62,14 @@ dependencies = [
|
|||||||
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.3.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "0.1.77"
|
version = "0.1.77"
|
||||||
@ -83,6 +92,14 @@ name = "strsim"
|
|||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempdir"
|
||||||
|
version = "0.3.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "term_size"
|
name = "term_size"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
@ -148,9 +165,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||||
"checksum libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "408014cace30ee0f767b1c4517980646a573ec61a57957aeeabcac8ac0a02e8d"
|
"checksum libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "408014cace30ee0f767b1c4517980646a573ec61a57957aeeabcac8ac0a02e8d"
|
||||||
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
|
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
|
||||||
|
"checksum rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2791d88c6defac799c3f20d74f094ca33b9332612d9aef9078519c82e4fe04a5"
|
||||||
"checksum regex 0.1.77 (registry+https://github.com/rust-lang/crates.io-index)" = "64b03446c466d35b42f2a8b203c8e03ed8b91c0f17b56e1f84f7210a257aa665"
|
"checksum regex 0.1.77 (registry+https://github.com/rust-lang/crates.io-index)" = "64b03446c466d35b42f2a8b203c8e03ed8b91c0f17b56e1f84f7210a257aa665"
|
||||||
"checksum regex-syntax 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279401017ae31cf4e15344aa3f085d0e2e5c1e70067289ef906906fdbe92c8fd"
|
"checksum regex-syntax 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279401017ae31cf4e15344aa3f085d0e2e5c1e70067289ef906906fdbe92c8fd"
|
||||||
"checksum strsim 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "50c069df92e4b01425a8bf3576d5d417943a6a7272fbabaf5bd80b1aaa76442e"
|
"checksum strsim 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "50c069df92e4b01425a8bf3576d5d417943a6a7272fbabaf5bd80b1aaa76442e"
|
||||||
|
"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
|
||||||
"checksum term_size 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f7f5f3f71b0040cecc71af239414c23fd3c73570f5ff54cf50e03cef637f2a0"
|
"checksum term_size 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f7f5f3f71b0040cecc71af239414c23fd3c73570f5ff54cf50e03cef637f2a0"
|
||||||
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
|
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
|
||||||
"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5"
|
"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5"
|
||||||
|
@ -10,3 +10,4 @@ homepage = "https://github.com/casey/j"
|
|||||||
|
|
||||||
regex = "^0.1.77"
|
regex = "^0.1.77"
|
||||||
clap = "^2.0.0"
|
clap = "^2.0.0"
|
||||||
|
tempdir = "^0.3.5"
|
||||||
|
2
justfile
2
justfile
@ -1,6 +1,6 @@
|
|||||||
test:
|
test:
|
||||||
cargo test
|
cargo test
|
||||||
cargo run -- quine
|
cargo run -- quine clean > /dev/null 2> /dev/null
|
||||||
|
|
||||||
# list all recipies
|
# list all recipies
|
||||||
list:
|
list:
|
||||||
|
5
notes
5
notes
@ -2,12 +2,11 @@ notes
|
|||||||
-----
|
-----
|
||||||
|
|
||||||
-- report double compile error
|
-- report double compile error
|
||||||
-- actually run recipes
|
|
||||||
-- actually parse recipe and validate contents
|
|
||||||
-- think about maybe using multiple cores
|
|
||||||
-- should pre-requisite order really be arbitrary?
|
-- should pre-requisite order really be arbitrary?
|
||||||
-- test plan order
|
-- test plan order
|
||||||
|
|
||||||
|
-- use multiple cores
|
||||||
|
|
||||||
- look through all justfiles for features of make that I use. so far:
|
- look through all justfiles for features of make that I use. so far:
|
||||||
. phony
|
. phony
|
||||||
. SHELL := zsh
|
. SHELL := zsh
|
||||||
|
58
src/lib.rs
58
src/lib.rs
@ -5,7 +5,7 @@ extern crate regex;
|
|||||||
|
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
|
|
||||||
use std::{fs, fmt};
|
use std::{fs, fmt, process, io};
|
||||||
use std::collections::{BTreeMap, BTreeSet, HashSet};
|
use std::collections::{BTreeMap, BTreeSet, HashSet};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
@ -49,14 +49,46 @@ struct Recipe<'a> {
|
|||||||
dependencies: BTreeSet<&'a str>,
|
dependencies: BTreeSet<&'a str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn error_from_signal<'a>(recipe: &'a str, exit_status: process::ExitStatus) -> RunError<'a> {
|
||||||
|
use std::os::unix::process::ExitStatusExt;
|
||||||
|
match exit_status.signal() {
|
||||||
|
Some(signal) => RunError::Signal{recipe: recipe, signal: signal},
|
||||||
|
None => RunError::UnknownFailure{recipe: recipe},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn error_from_signal<'a>(recipe: &'a str, exit_status: process::ExitStatus) -> RunError<'a> {
|
||||||
|
RunError::UnknownFailure{recipe: recipe}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Recipe<'a> {
|
impl<'a> Recipe<'a> {
|
||||||
fn run(&self) -> Result<(), RunError<'a>> {
|
fn run(&self) -> Result<(), RunError<'a>> {
|
||||||
// TODO: actually run recipes
|
|
||||||
warn!("running {}", self.name);
|
|
||||||
for command in &self.commands {
|
for command in &self.commands {
|
||||||
|
let mut command = *command;
|
||||||
|
if !command.starts_with("@") {
|
||||||
warn!("{}", command);
|
warn!("{}", command);
|
||||||
|
} else {
|
||||||
|
command = &command[1..];
|
||||||
|
}
|
||||||
|
let status = process::Command::new("sh")
|
||||||
|
.arg("-c")
|
||||||
|
.arg(command)
|
||||||
|
.status();
|
||||||
|
try!(match status {
|
||||||
|
Ok(exit_status) => if let Some(code) = exit_status.code() {
|
||||||
|
if code == 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(RunError::Code{recipe: self.name, code: code})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(error_from_signal(self.name, exit_status))
|
||||||
|
},
|
||||||
|
Err(io_error) => Err(RunError::IoError{recipe: self.name, io_error: io_error})
|
||||||
|
});
|
||||||
}
|
}
|
||||||
// Err(RunError::Code{recipe: self.name, code: -1})
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -270,10 +302,13 @@ impl<'a> Justfile<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum RunError<'a> {
|
pub enum RunError<'a> {
|
||||||
UnknownRecipes{recipes: Vec<&'a str>},
|
UnknownRecipes{recipes: Vec<&'a str>},
|
||||||
// Signal{recipe: &'a str, signal: i32},
|
Signal{recipe: &'a str, signal: i32},
|
||||||
Code{recipe: &'a str, code: i32},
|
Code{recipe: &'a str, code: i32},
|
||||||
|
UnknownFailure{recipe: &'a str},
|
||||||
|
IoError{recipe: &'a str, io_error: io::Error},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Display for RunError<'a> {
|
impl<'a> Display for RunError<'a> {
|
||||||
@ -289,6 +324,19 @@ impl<'a> Display for RunError<'a> {
|
|||||||
&RunError::Code{recipe, code} => {
|
&RunError::Code{recipe, code} => {
|
||||||
try!(write!(f, "Recipe \"{}\" failed with code {}", recipe, code));
|
try!(write!(f, "Recipe \"{}\" failed with code {}", recipe, code));
|
||||||
},
|
},
|
||||||
|
&RunError::Signal{recipe, signal} => {
|
||||||
|
try!(write!(f, "Recipe \"{}\" wast terminated by signal {}", recipe, signal));
|
||||||
|
}
|
||||||
|
&RunError::UnknownFailure{recipe} => {
|
||||||
|
try!(write!(f, "Recipe \"{}\" failed for an unknown reason", recipe));
|
||||||
|
},
|
||||||
|
&RunError::IoError{recipe, ref io_error} => {
|
||||||
|
try!(match io_error.kind() {
|
||||||
|
io::ErrorKind::NotFound => write!(f, "Recipe \"{}\" could not be run because j could not find `sh` the command:\n{}", recipe, io_error),
|
||||||
|
io::ErrorKind::PermissionDenied => write!(f, "Recipe \"{}\" could not be run because j could not run `sh`:\n{}", recipe, io_error),
|
||||||
|
_ => write!(f, "Recipe \"{}\" could not be run because of an IO error while launching the `sh`:\n{}", recipe, io_error),
|
||||||
|
});
|
||||||
|
},
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
42
src/tests.rs
42
src/tests.rs
@ -1,3 +1,5 @@
|
|||||||
|
extern crate tempdir;
|
||||||
|
|
||||||
use super::{ErrorKind, Justfile};
|
use super::{ErrorKind, Justfile};
|
||||||
|
|
||||||
fn expect_error(text: &str, line: usize, expected_error_kind: ErrorKind) {
|
fn expect_error(text: &str, line: usize, expected_error_kind: ErrorKind) {
|
||||||
@ -130,3 +132,43 @@ fn first() {
|
|||||||
let justfile = expect_success("#hello\n#goodbye\na:\nb:\nc:\n");
|
let justfile = expect_success("#hello\n#goodbye\na:\nb:\nc:\n");
|
||||||
assert!(justfile.first().unwrap() == "a");
|
assert!(justfile.first().unwrap() == "a");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unknown_recipes() {
|
||||||
|
match expect_success("a:\nb:\nc:").run(&["a", "x", "y", "z"]).unwrap_err() {
|
||||||
|
super::RunError::UnknownRecipes{recipes} => assert_eq!(recipes, &["x", "y", "z"]),
|
||||||
|
other @ _ => panic!("expected an unknown recipe error, but got: {}", other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn code_error() {
|
||||||
|
match expect_success("fail:\n @function x { return 100; }; x").run(&["fail"]).unwrap_err() {
|
||||||
|
super::RunError::Code{recipe, code} => {
|
||||||
|
assert_eq!(recipe, "fail");
|
||||||
|
assert_eq!(code, 100);
|
||||||
|
},
|
||||||
|
other @ _ => panic!("expected an code run error, but got: {}", other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn run_order() {
|
||||||
|
let tmp = tempdir::TempDir::new("run_order").unwrap_or_else(|err| panic!("tmpdir: failed to create temporary directory: {}", err));
|
||||||
|
let path = tmp.path().to_str().unwrap_or_else(|| panic!("tmpdir: path was not valid UTF-8")).to_owned();
|
||||||
|
let text = r"
|
||||||
|
a:
|
||||||
|
@touch a
|
||||||
|
|
||||||
|
b: a
|
||||||
|
@mv a b
|
||||||
|
|
||||||
|
c: b
|
||||||
|
@mv b c
|
||||||
|
|
||||||
|
d: c
|
||||||
|
@rm c
|
||||||
|
";
|
||||||
|
super::std::env::set_current_dir(path).expect("failed to set current directory");
|
||||||
|
expect_success(text).run(&["a", "d"]).unwrap();
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user