Skip to content

Commit

Permalink
refact: uses spawning shell instead of parsing cmds (#47)
Browse files Browse the repository at this point in the history
  • Loading branch information
cristianoliveira committed May 21, 2023
1 parent 837dcb2 commit 793c973
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 135 deletions.
7 changes: 6 additions & 1 deletion examples/complex-commands.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
- name: run my test
run: "echo 'foo bar baz' | sed 's/foo/bar/g'"
run: "echo 'foo bar baz' | sed 's/foo/FIRST/g'"
change: "**"
run_on_init: true

- name: run my test
run: "ls | sed 's/Cargo/Foo/g'"
change: "**"
run_on_init: true
5 changes: 3 additions & 2 deletions src/cli/watch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,18 @@ impl WatchCommand {
}

fn run(&self, commands: &Vec<String>) -> Result<(), String> {
clear_shell();
for command in commands {
if self.verbose {
println!("command: {:?}", command)
};
println!(" ----- funzzy running: {} -------", command);
cmd::execute(String::from(command))?
}
Ok(())
}

fn run_rules(&self, rules: Vec<Vec<String>>) -> Result<(), String> {
clear_shell();
let results = rules.iter().map(|rule_cmds| {
self.run(&rule_cmds)
}).find(|r| {
Expand Down Expand Up @@ -79,7 +80,7 @@ impl Command for WatchCommand {
self.run_rules(rules)?
}

println!("Watching.");
println!("Watching...");
while let Ok(event) = rx.recv() {
if let DebouncedEvent::Create(path) = event {
let path_str = path.into_os_string().into_string().unwrap();
Expand Down
145 changes: 13 additions & 132 deletions src/cmd.rs
Original file line number Diff line number Diff line change
@@ -1,145 +1,26 @@
use std::process::{ Command, Stdio };

fn command_parser(command: String) -> Vec<Command> {
let formatted = command.replace("'", " ' ").replace("\"", " \" ");
let mut tokens: Vec<&str> = formatted.split(' ').collect();

let init = tokens.remove(0);
let mut current_cmd = Command::new(init);
while tokens.len() > 0 {
let token = tokens.remove(0);
match token.clone() {
"|" | "||" | "&" | "&&" => {
current_cmd.stdout(Stdio::piped());

let cmdname = tokens.remove(0);
let mut cmd = Command::new(cmdname);
let result = current_cmd.spawn().unwrap().stdout.unwrap();
cmd.stdin(Stdio::from(result));
current_cmd = cmd;
}

"\"" => {
let mut string_arg = String::new();
while tokens.len() > 0 {
let token = tokens.remove(0);
if token == "\"" {
string_arg.pop();
current_cmd.arg(string_arg);
break;
}
string_arg.push_str(token);
string_arg.push_str(" ");
}
}

"'" => {
let mut string_arg = String::new();
while tokens.len() > 0 {
let token = tokens.remove(0);
if token == "'" {
string_arg.pop();
current_cmd.arg(string_arg);
break;
}
string_arg.push_str(token);
string_arg.push_str(" ");
}
}

arg if arg.len() > 0 => {
current_cmd.arg(arg);
}

_ => {}
}
}

vec![current_cmd]
}
use std::process::{ Command };

pub fn execute(command_line: String) -> Result<(), String> {
println!(" ----- funzzy running: {} -------", command_line);
let commands = command_parser(command_line);

for mut cmd in commands {
if let Err(error) = cmd.status() {
return Err(String::from(error.to_string()));
let shell = std::env::var("SHELL").unwrap_or(String::from("/bin/sh"));
let mut cmd = Command::new(shell);
match cmd.arg("-c").arg(command_line).status() {
Err(error) => return Err(String::from(error.to_string())),
Ok(status) => {
if status.success() {
return Ok(());
} else {
return Err(String::from("Command failed"));
}
}
}

return Ok(());
};
}

#[test]
fn it_executes_a_command() {
let result = match execute(String::from("echo 'foo'")) {
Ok(_) => true,
Err(msg) => panic!(msg),
Err(err) => panic!("{:?}",err),
};

assert!(result)
}

#[test]
fn it_creates_commands() {
let result = command_parser(String::from("cargo build"));

let mut expected = Command::new("cargo");
expected.arg("build");
assert_eq!(format!("{:?}", expected), format!("{:?}", result[0]))
}

#[test]
fn it_creates_commands_with_more_than_one_arg() {
let result = command_parser(String::from("cargo build --verbose"));

let mut expected = Command::new("cargo");
expected.arg("build");
expected.arg("--verbose");
assert_eq!(format!("{:?}", expected), format!("{:?}", result[0]))
}

#[test]
fn it_accept_nested_commands_and_return_the_latest() {
let result = command_parser(String::from("cargo build --verbose && cargo test"));

let mut cmd2 = Command::new("cargo");
cmd2.arg("test");

let commands = vec![cmd2];

assert_eq!(format!("{:?}", commands), format!("{:?}", result))
}


#[test]
fn it_allows_piping_outputs() {
let mut commands = command_parser(
String::from("echo 'foo' | sed 's/foo/bar/g'")
);

let mut child = commands.remove(0);

let output = child.stdout(Stdio::piped())
.spawn()
.expect("Failed to start sed process")
.wait_with_output()
.expect("Failed to wait on sed");

let result = output.stdout.as_slice();

assert_eq!("bar\n", String::from_utf8_lossy(result));
}

#[test]
fn it_accept_strings_as_arguments() {
let result = command_parser(String::from("echo 'foo bar baz'"));

let mut cmd2 = Command::new("echo");
cmd2.arg("foo bar baz");

let commands = vec![cmd2];

assert_eq!(format!("{:?}", commands), format!("{:?}", result))
}

0 comments on commit 793c973

Please sign in to comment.