From 27124c2a832d1c9ecbc1f8ebef8108ee6e2621f7 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 12 May 2016 18:49:14 +0200 Subject: [PATCH 1/3] Rewrite imag binary in Rust --- bin/Cargo.toml | 10 +++ bin/imag | 79 ---------------------- bin/src/main.rs | 174 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 184 insertions(+), 79 deletions(-) create mode 100644 bin/Cargo.toml delete mode 100755 bin/imag create mode 100644 bin/src/main.rs diff --git a/bin/Cargo.toml b/bin/Cargo.toml new file mode 100644 index 00000000..b9d6cf22 --- /dev/null +++ b/bin/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "imag" +version = "0.1.0" +authors = ["Matthias Beyer "] + +[dependencies] +version = "2.0" +walkdir = "0.1.5" +crossbeam = "0.2.9" + diff --git a/bin/imag b/bin/imag deleted file mode 100755 index 552ea9b4..00000000 --- a/bin/imag +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env bash - -version() { - echo "0.1.0" -} - -help() { - local cmds="$(commands)" - - echo " _ "; - echo " (_)_ __ ___ __ _ __ _ "; - echo " | | '_ \` _ \ / _\` |/ _\` |"; - echo " | | | | | | | (_| | (_| |"; - echo " |_|_| |_| |_|\__,_|\__, |"; - echo " |___/ "; - echo " -------------------------"; - cat < - - imag - the personal information management suite for the commandline - - imag is a PIM suite for the commandline. It consists of several commands, - called "modules". Each module implements one PIM aspect and all of these - modules can be used independently. - - Available commands: - $(for cmd in $cmds; do - echo -e "\t$(echo $cmd | sed -r 's,(.*)/imag-(.*),\2,')"; - done) - - Call a command with "imag " - Each command can be called with "--help" to get the respective helptext. - - Please visit https://github.com/matthiasbeyer/imag to view the source code, - follow the development of imag or maybe even contribute to imag. - - imag is free software. It is released under the terms of LGPLv2.1 - - (c) 2016 Matthias Beyer and contributors -EOS -} - -commands() { - [[ ! -z "$IMAG_IS_THE_SHIT" ]] && \ - find $IMAG_IS_THE_SHIT -type f -iname "imag-*" -print 2>/dev/null - find ${PATH//:/ } -maxdepth 1 -type f -iname "imag-*" -print 2>/dev/null -} - -main() { - case $1 in - --versions) - echo -n "imag "; version - for command in $(commands); do - $command --version - done - exit 0 - ;; - - --version) - version - exit 0 - ;; - - --help | -h) - help - exit 0 - ;; - - *) - local cmd=$1; shift - local executable=$(commands | grep $cmd | head -n 1) - exec $executable $* - ;; - - esac -} - -main $* diff --git a/bin/src/main.rs b/bin/src/main.rs new file mode 100644 index 00000000..7e23d5b7 --- /dev/null +++ b/bin/src/main.rs @@ -0,0 +1,174 @@ +extern crate crossbeam; +#[macro_use] extern crate version; +extern crate walkdir; + +use std::env; +use std::process::exit; +use std::process::Command; +use std::process::Stdio; +use std::io::ErrorKind; + +use walkdir::WalkDir; +use crossbeam::*; + +fn help(cmds: Vec) { + println!(r#" + + _ + (_)_ __ ___ __ _ __ _ + | | '_ \` _ \/ _\`|/ _\`| + | | | | | | | (_| | (_| | + |_|_| |_| |_|\__,_|\__, | + |___/ + ------------------------- + + Usage: imag [--version | --versions | -h | --help] + + imag - the personal information management suite for the commandline + + imag is a PIM suite for the commandline. It consists of several commands, + called "modules". Each module implements one PIM aspect and all of these + modules can be used independently. + + Available commands: + "#); + + for cmd in cmds.iter() { + println!("\t{}", cmd); + } + + println!(r#" + + Call a command with 'imag ' + Each command can be called with "--help" to get the respective helptext. + + Please visit https://github.com/matthiasbeyer/imag to view the source code, + follow the development of imag or maybe even contribute to imag. + + imag is free software. It is released under the terms of LGPLv2.1 + + (c) 2016 Matthias Beyer and contributors"#); +} + +fn get_commands() -> Vec { + let path = env::var("PATH"); + if path.is_err() { + println!("PATH error: {:?}", path); + exit(1); + } + let pathelements = path.unwrap(); + let pathelements = pathelements.split(":"); + + let joinhandles : Vec>> = pathelements + .map(|elem| { + crossbeam::scope(|scope| { + scope.spawn(|| { + WalkDir::new(elem) + .max_depth(1) + .into_iter() + .filter(|path| { + match path { + &Ok(ref path) => path.path().starts_with(format!("{}/imag-", elem)), + &Err(_) => false, + } + }) + .filter_map(|x| x.ok()) + .map(|path| { + path.path() + .to_str() + .map(String::from) + }) + .filter_map(|x| x) + .collect() + }) + }) + }) + .collect(); + + let mut execs = vec![]; + for joinhandle in joinhandles.into_iter() { + let mut v = joinhandle.join(); + execs.append(&mut v); + } + + execs +} + +fn main() { + let commands = get_commands(); + let mut args = env::args(); + let _ = args.next(); + let first_arg = match args.next() { + Some(s) => s, + None => { + help(commands); + exit(0); + }, + }; + + match &first_arg[..] { + "--help" | "-h" => { + help(commands); + exit(0); + }, + + "--version" => println!("imag {}", &version!()[..]), + + "--versions" => { + let mut result = vec![]; + for command in commands.iter() { + result.push(crossbeam::scope(|scope| { + scope.spawn(|| { + let v = Command::new(command).arg("--version").output(); + match v { + Ok(v) => match String::from_utf8(v.stdout) { + Ok(s) => format!("{} -> {}", command, s), + Err(e) => format!("Failed calling {} -> {:?}", command, e), + }, + Err(e) => format!("Failed calling {} -> {:?}", command, e), + } + }) + })) + } + + for versionstring in result.into_iter().map(|handle| handle.join()) { + println!("{}", versionstring); + } + }, + + s => { + match Command::new(format!("imag-{}", s)) + .stdin(Stdio::inherit()) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .spawn() + .and_then(|mut handle| handle.wait()) + { + Ok(exit_status) => { + if !exit_status.success() { + println!("{} exited with non-zero exit code", s); + exit(exit_status.code().unwrap_or(42)); + } + }, + + Err(e) => { + match e.kind() { + ErrorKind::NotFound => { + println!("No such command: 'imag-{}'", s); + exit(2); + }, + ErrorKind::PermissionDenied => { + println!("No permission to execute: 'imag-{}'", s); + exit(1); + }, + _ => { + println!("Error spawning: {:?}", e); + exit(1337); + } + } + } + } + + }, + } +} From 580c9e5286bddd5cea02721e72438a786edbb1b5 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 13 May 2016 14:41:11 +0200 Subject: [PATCH 2/3] Add command finder helper function --- bin/src/main.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bin/src/main.rs b/bin/src/main.rs index 7e23d5b7..925fb49f 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -94,11 +94,15 @@ fn get_commands() -> Vec { execs } +fn find_command() -> Option { + env::args().skip(1).filter(|x| !x.starts_with("-")).next() +} + fn main() { let commands = get_commands(); let mut args = env::args(); let _ = args.next(); - let first_arg = match args.next() { + let first_arg = match find_command() { Some(s) => s, None => { help(commands); From eca41e04dd8879592fba1a900342e817c3543555 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 13 May 2016 14:41:19 +0200 Subject: [PATCH 3/3] Add argument finder helper function --- bin/src/main.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/bin/src/main.rs b/bin/src/main.rs index 925fb49f..3b154a47 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -98,6 +98,14 @@ fn find_command() -> Option { env::args().skip(1).filter(|x| !x.starts_with("-")).next() } +fn find_args(command: &str) -> Vec { + env::args() + .skip(1) + .position(|e| e == command) + .map(|pos| env::args().skip(pos + 2).collect::>()) + .unwrap_or(vec![]) +} + fn main() { let commands = get_commands(); let mut args = env::args(); @@ -145,6 +153,7 @@ fn main() { .stdin(Stdio::inherit()) .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) + .args(&find_args(s)[..]) .spawn() .and_then(|mut handle| handle.wait()) {