2016-05-12 16:49:14 +00:00
|
|
|
extern crate crossbeam;
|
2016-08-06 15:43:28 +00:00
|
|
|
extern crate clap;
|
2016-05-12 16:49:14 +00:00
|
|
|
#[macro_use] extern crate version;
|
2016-09-01 09:24:31 +00:00
|
|
|
#[macro_use] extern crate log;
|
2016-05-12 16:49:14 +00:00
|
|
|
extern crate walkdir;
|
|
|
|
|
2016-08-06 15:44:28 +00:00
|
|
|
extern crate libimagrt;
|
|
|
|
|
2016-05-12 16:49:14 +00:00
|
|
|
use std::env;
|
|
|
|
use std::process::exit;
|
|
|
|
use std::process::Command;
|
|
|
|
use std::process::Stdio;
|
|
|
|
use std::io::ErrorKind;
|
|
|
|
|
|
|
|
use walkdir::WalkDir;
|
|
|
|
use crossbeam::*;
|
2016-09-01 09:24:53 +00:00
|
|
|
use clap::{Arg, App, AppSettings, SubCommand};
|
2016-05-12 16:49:14 +00:00
|
|
|
|
2016-08-06 15:55:52 +00:00
|
|
|
use libimagrt::runtime::Runtime;
|
2016-09-01 09:24:53 +00:00
|
|
|
use libimagrt::setup::generate_runtime_setup;
|
2016-07-21 22:08:11 +00:00
|
|
|
|
2016-05-12 16:49:14 +00:00
|
|
|
fn help(cmds: Vec<String>) {
|
|
|
|
println!(r#"
|
|
|
|
|
|
|
|
_
|
|
|
|
(_)_ __ ___ __ _ __ _
|
|
|
|
| | '_ \` _ \/ _\`|/ _\`|
|
|
|
|
| | | | | | | (_| | (_| |
|
|
|
|
|_|_| |_| |_|\__,_|\__, |
|
|
|
|
|___/
|
|
|
|
-------------------------
|
|
|
|
|
|
|
|
Usage: imag [--version | --versions | -h | --help] <command> <args...>
|
|
|
|
|
|
|
|
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 <command> <args>'
|
|
|
|
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<String> {
|
|
|
|
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<ScopedJoinHandle<Vec<String>>> = pathelements
|
|
|
|
.map(|elem| {
|
|
|
|
crossbeam::scope(|scope| {
|
|
|
|
scope.spawn(|| {
|
|
|
|
WalkDir::new(elem)
|
|
|
|
.max_depth(1)
|
|
|
|
.into_iter()
|
|
|
|
.filter(|path| {
|
|
|
|
match path {
|
2016-07-04 14:23:45 +00:00
|
|
|
&Ok(ref p) => p.file_name()
|
|
|
|
.to_str()
|
|
|
|
.map_or(false, |filename| filename.starts_with("imag-")),
|
2016-05-12 16:49:14 +00:00
|
|
|
&Err(_) => false,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.filter_map(|x| x.ok())
|
2016-07-04 14:23:45 +00:00
|
|
|
.filter_map(|path| {
|
|
|
|
path.file_name()
|
|
|
|
.to_str()
|
2016-08-07 13:11:48 +00:00
|
|
|
.and_then(|s| s.splitn(2, "-").nth(1).map(String::from))
|
2016-05-12 16:49:14 +00:00
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
let mut execs = vec![];
|
|
|
|
for joinhandle in joinhandles.into_iter() {
|
|
|
|
let mut v = joinhandle.join();
|
|
|
|
execs.append(&mut v);
|
|
|
|
}
|
|
|
|
|
|
|
|
execs
|
|
|
|
}
|
|
|
|
|
2016-09-01 09:24:53 +00:00
|
|
|
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
|
|
|
get_commands()
|
2016-08-07 13:19:20 +00:00
|
|
|
.iter()
|
2016-09-01 09:24:53 +00:00
|
|
|
.fold(app, |app, cmd| app.subcommand(SubCommand::with_name(cmd)))
|
2016-08-07 13:19:20 +00:00
|
|
|
.arg(Arg::with_name("version")
|
|
|
|
.long("version")
|
|
|
|
.takes_value(false)
|
|
|
|
.required(false)
|
|
|
|
.multiple(false)
|
|
|
|
.help("Get the version of imag"))
|
|
|
|
.arg(Arg::with_name("versions")
|
|
|
|
.long("versions")
|
|
|
|
.takes_value(false)
|
|
|
|
.required(false)
|
|
|
|
.multiple(false)
|
|
|
|
.help("Get the versions of the imag commands"))
|
|
|
|
.arg(Arg::with_name("help")
|
|
|
|
.long("help")
|
|
|
|
.short("h")
|
|
|
|
.takes_value(false)
|
|
|
|
.required(false)
|
|
|
|
.multiple(false)
|
|
|
|
.help("Show help"))
|
2016-08-26 14:35:15 +00:00
|
|
|
.subcommand(SubCommand::with_name("help").help("Show help"))
|
|
|
|
.settings(&[AppSettings::AllowExternalSubcommands])
|
2016-09-01 09:24:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
let appname = "imag";
|
|
|
|
let version = &version!();
|
|
|
|
let about = "imag - the PIM suite for the commandline";
|
|
|
|
let rt = generate_runtime_setup(appname, version, about, build_ui);
|
|
|
|
let matches = rt.cli();
|
2016-08-06 15:55:52 +00:00
|
|
|
|
2016-09-01 09:24:53 +00:00
|
|
|
debug!("matches: {:?}", matches);
|
2016-08-07 12:31:34 +00:00
|
|
|
if matches.is_present("help") {
|
2016-09-01 09:24:53 +00:00
|
|
|
debug!("Calling help()");
|
2016-08-07 12:31:34 +00:00
|
|
|
help(get_commands());
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
2016-08-06 15:55:52 +00:00
|
|
|
if matches.is_present("version") {
|
2016-09-01 09:24:53 +00:00
|
|
|
debug!("Showing version");
|
2016-08-06 15:55:52 +00:00
|
|
|
println!("imag {}", &version!()[..]);
|
|
|
|
exit(0);
|
|
|
|
}
|
2016-05-13 12:41:19 +00:00
|
|
|
|
2016-08-06 15:55:52 +00:00
|
|
|
if matches.is_present("versions") {
|
2016-09-01 09:24:53 +00:00
|
|
|
debug!("Showing versions");
|
2016-08-06 15:55:52 +00:00
|
|
|
let mut result = vec![];
|
2016-09-01 09:24:53 +00:00
|
|
|
for command in get_commands().iter() {
|
2016-08-06 15:55:52 +00:00
|
|
|
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),
|
2016-05-12 16:49:14 +00:00
|
|
|
Err(e) => format!("Failed calling {} -> {:?}", command, e),
|
2016-08-06 15:55:52 +00:00
|
|
|
},
|
|
|
|
Err(e) => format!("Failed calling {} -> {:?}", command, e),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}))
|
|
|
|
}
|
2016-05-12 16:49:14 +00:00
|
|
|
|
2016-08-06 15:55:52 +00:00
|
|
|
for versionstring in result.into_iter().map(|handle| handle.join()) {
|
|
|
|
println!("{}", versionstring);
|
|
|
|
}
|
|
|
|
}
|
2016-05-12 16:49:14 +00:00
|
|
|
|
2016-08-06 15:55:52 +00:00
|
|
|
matches.subcommand_name()
|
|
|
|
.map(|subcommand| {
|
|
|
|
|
|
|
|
let mut subcommand_args = vec![];
|
|
|
|
|
|
|
|
for arg in Runtime::arg_names() {
|
|
|
|
matches.value_of(arg)
|
|
|
|
.map(|value| {
|
|
|
|
subcommand_args.push(arg);
|
|
|
|
subcommand_args.push(value);
|
|
|
|
});
|
2016-07-19 18:43:48 +00:00
|
|
|
}
|
2016-08-06 15:55:52 +00:00
|
|
|
|
|
|
|
match Command::new(format!("imag-{}", subcommand))
|
2016-05-12 16:49:14 +00:00
|
|
|
.stdin(Stdio::inherit())
|
|
|
|
.stdout(Stdio::inherit())
|
|
|
|
.stderr(Stdio::inherit())
|
2016-07-19 18:57:49 +00:00
|
|
|
.args(&subcommand_args[..])
|
2016-05-12 16:49:14 +00:00
|
|
|
.spawn()
|
|
|
|
.and_then(|mut handle| handle.wait())
|
|
|
|
{
|
|
|
|
Ok(exit_status) => {
|
|
|
|
if !exit_status.success() {
|
2016-08-06 15:55:52 +00:00
|
|
|
println!("{} exited with non-zero exit code", subcommand);
|
2016-05-12 16:49:14 +00:00
|
|
|
exit(exit_status.code().unwrap_or(42));
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
Err(e) => {
|
|
|
|
match e.kind() {
|
|
|
|
ErrorKind::NotFound => {
|
2016-08-06 15:55:52 +00:00
|
|
|
println!("No such command: 'imag-{}'", subcommand);
|
2016-05-12 16:49:14 +00:00
|
|
|
exit(2);
|
|
|
|
},
|
|
|
|
ErrorKind::PermissionDenied => {
|
2016-08-06 15:55:52 +00:00
|
|
|
println!("No permission to execute: 'imag-{}'", subcommand);
|
2016-05-12 16:49:14 +00:00
|
|
|
exit(1);
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
println!("Error spawning: {:?}", e);
|
|
|
|
exit(1337);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-08-06 15:55:52 +00:00
|
|
|
});
|
2016-05-12 16:49:14 +00:00
|
|
|
}
|