Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement JSON output for better interoperability #1

Merged
merged 6 commits into from
Dec 12, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "siren"
version = "1.0.3"
version = "1.1.0"
authors = ["Alessio Biancalana <dottorblaster@gmail.com>"]
description = "Your friendly neighborhood monitoring CLI tool."
homepage = "https://github.com/dottorblaster/siren"
65 changes: 44 additions & 21 deletions src/execute.rs
Original file line number Diff line number Diff line change
@@ -1,54 +1,77 @@
extern crate ansi_term;
extern crate serde_json;

use parse_config::Task;
use task_output::SerializableOutput;
use task_output;
use std::sync::{Mutex, Arc};
use std::thread;
use std::process::Command;
use std::process::Output;

use self::ansi_term::Colour::{Red, Green, Yellow, Black};
use self::ansi_term::ANSIString;

fn task_success(task: Task, output: Output) {
let stdout = ANSIString::from(String::from_utf8(output.stdout).unwrap());
println!(
"{} {}\n{}\n",
Black.bold().on(Green).paint(" SUCCESS "),
Yellow.paint(format!("{}", task.name)),
stdout
);
fn task_success(task: Task, output: Output, json: bool) {
if json == false {
let stdout = ANSIString::from(String::from_utf8(output.stdout).unwrap());
println!(
"{} {}\n{}\n",
Black.bold().on(Green).paint(" SUCCESS "),
Yellow.paint(format!("{}", task.name)),
stdout
);
}
}

fn task_failure(task: Task, output: Output) {
let stderr = ANSIString::from(String::from_utf8(output.stderr).unwrap());
println!(
"{} {}\n{}\n",
Black.bold().on(Red).paint(" FAIL "),
Yellow.paint(format!("{}", task.name)),
stderr
);
fn task_failure(task: Task, output: Output, json: bool) {
if json == false {
let stderr = ANSIString::from(String::from_utf8(output.stderr).unwrap());
println!(
"{} {}\n{}\n",
Black.bold().on(Red).paint(" FAIL "),
Yellow.paint(format!("{}", task.name)),
stderr
);
}
}

fn print_json(outputs: Arc<Mutex<Vec<task_output::TaskOutput>>>, json: bool) {
if json == true {
let slice = &*outputs.lock().unwrap();
let serializable_output = SerializableOutput { tasks: slice.to_vec() };
println!("{}", serde_json::to_string(&serializable_output).unwrap());
}
}

pub fn run(tasks: Vec<Task>, cwd_path: String) -> bool {
pub fn run(tasks: Vec<Task>, cwd_path: String, json_output: bool) -> bool {
let outputs = Arc::new(Mutex::new(task_output::Tasks::with_capacity(tasks.len())));
let mut handles = Vec::with_capacity(tasks.len());
println!("\n");
for task in &tasks {
let (data, path) = (task.clone(), cwd_path.clone());
let outputs = Arc::clone(&outputs);
let child = thread::spawn(move || {
let local_task = data.clone();
let task_data = data.clone();
let mut iter = local_task.command.split_whitespace();
let output = Command::new(iter.nth(0).unwrap())
let mut list = outputs.lock().unwrap();
let command_output = Command::new(iter.nth(0).unwrap())
.args(iter)
.current_dir(path)
.output()
.expect("command failed");
match output.status.code() {
Some(0) => task_success(data, output),
Some(_) => task_failure(data, output),
let cloned_output = command_output.clone();
list.push(task_output::build_task_output(cloned_output, task_data));
match command_output.status.code() {
Some(0) => task_success(data, command_output, json_output),
Some(_) => task_failure(data, command_output, json_output),
None => println!("Process terminated by signal")
}
});
handles.push(child);
}
for handle in handles { handle.join().unwrap(); }
print_json(outputs, json_output);
true
}
12 changes: 10 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@ use clap::{Arg, App};

mod parse_config;
mod execute;
mod task_output;

fn parentpath(path: String) -> String {
let mut v: Vec<&str> = path.split("/").collect();
@@ -30,7 +31,7 @@ fn read_sirenfile(sirenfile_path: String) -> Result<String, IoError> {

fn main() {
let matches = App::new("Siren")
.version("1.0.3")
.version("1.1.0")
.author("Alessio Biancalana <dottorblaster@gmail.com>")
.about("Your tiny friendly rusty neighborhood monitoring CLI tool")
.arg(Arg::with_name("file")
@@ -39,9 +40,16 @@ fn main() {
.value_name("FILE")
.help("Sets a custom Sirenfile")
.takes_value(true))
.arg(Arg::with_name("json-output")
.short("j")
.long("json-output")
.value_name("JSON")
.help("Enable JSON output")
.takes_value(false))
.get_matches();

let sirenfile_path = matches.value_of("file").unwrap_or("./Sirenfile.json").to_owned();
let output_json = matches.is_present("json-output");

let configstring = match read_sirenfile(sirenfile_path) {
Ok(jsoncontent) => jsoncontent,
@@ -55,5 +63,5 @@ fn main() {
true => parentpath(matches.value_of("file").unwrap_or("./Sirenfile.json").to_owned()),
false => String::from(".")
};
execute::run(conf.tasks, cwd_path);
execute::run(conf.tasks, cwd_path, output_json);
}
31 changes: 31 additions & 0 deletions src/task_output.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
extern crate serde;
extern crate serde_json;

use parse_config::Task;
use std::process::Output;

#[derive(Serialize, Clone)]
pub struct TaskOutput {
pub outcome: String,
pub code: String,
pub name: String,
pub description: String,
pub command: String,
}

pub type Tasks = Vec<TaskOutput>;

#[derive(Serialize, Clone)]
pub struct SerializableOutput {
pub tasks: Vec<TaskOutput>,
}

pub fn build_task_output(output: Output, task: Task) -> TaskOutput {
TaskOutput {
outcome: String::from_utf8(output.stdout).unwrap(),
code: output.status.code().unwrap().to_string(),
name: task.name,
description: task.description,
command: task.command,
}
}