Merge pull request #1373 from matthiasbeyer/libimagrt/handle-unknown-subcommand
libimagrt: Handle unknown subcommand
This commit is contained in:
commit
8492f149be
17 changed files with 177 additions and 31 deletions
|
@ -57,7 +57,6 @@ use libimagrt::runtime::Runtime;
|
||||||
use libimagrt::setup::generate_runtime_setup;
|
use libimagrt::setup::generate_runtime_setup;
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagstore::storeid::IntoStoreId;
|
use libimagstore::storeid::IntoStoreId;
|
||||||
use libimagutil::warn_exit::warn_exit;
|
|
||||||
|
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
|
@ -75,7 +74,13 @@ fn main() {
|
||||||
"add" => add(&rt),
|
"add" => add(&rt),
|
||||||
"remove" => remove(&rt),
|
"remove" => remove(&rt),
|
||||||
"list" => list(&rt),
|
"list" => list(&rt),
|
||||||
_ => warn_exit("No commandline call", 1)
|
other => {
|
||||||
|
debug!("Unknown command");
|
||||||
|
let _ = rt.handle_unknown_subcommand("imag-annotation", other, rt.cli())
|
||||||
|
.map_err_trace_exit_unwrap(1)
|
||||||
|
.code()
|
||||||
|
.map(std::process::exit);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,6 @@ use libimagentrygps::types::*;
|
||||||
use libimagentrygps::entry::*;
|
use libimagentrygps::entry::*;
|
||||||
use libimagrt::setup::generate_runtime_setup;
|
use libimagrt::setup::generate_runtime_setup;
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagutil::warn_exit::warn_exit;
|
|
||||||
use libimagerror::trace::MapErrTrace;
|
use libimagerror::trace::MapErrTrace;
|
||||||
use libimagerror::exit::ExitUnwrap;
|
use libimagerror::exit::ExitUnwrap;
|
||||||
use libimagerror::io::ToExitCode;
|
use libimagerror::io::ToExitCode;
|
||||||
|
@ -75,7 +74,13 @@ fn main() {
|
||||||
"add" => add(&rt),
|
"add" => add(&rt),
|
||||||
"remove" => remove(&rt),
|
"remove" => remove(&rt),
|
||||||
"get" => get(&rt),
|
"get" => get(&rt),
|
||||||
_ => warn_exit("No commandline call", 1)
|
other => {
|
||||||
|
debug!("Unknown command");
|
||||||
|
let _ = rt.handle_unknown_subcommand("imag-gps", other, rt.cli())
|
||||||
|
.map_err_trace_exit_unwrap(1)
|
||||||
|
.code()
|
||||||
|
.map(::std::process::exit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,7 +104,13 @@ fn main() {
|
||||||
"remove" => remove_linking(&rt),
|
"remove" => remove_linking(&rt),
|
||||||
"unlink" => unlink(&rt),
|
"unlink" => unlink(&rt),
|
||||||
"list" => list_linkings(&rt),
|
"list" => list_linkings(&rt),
|
||||||
_ => panic!("BUG"),
|
other => {
|
||||||
|
debug!("Unknown command");
|
||||||
|
let _ = rt.handle_unknown_subcommand("imag-link", other, rt.cli())
|
||||||
|
.map_err_trace_exit_unwrap(1)
|
||||||
|
.code()
|
||||||
|
.map(::std::process::exit);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
|
|
|
@ -67,8 +67,12 @@ fn main() {
|
||||||
match name {
|
match name {
|
||||||
"deref" => deref(&rt),
|
"deref" => deref(&rt),
|
||||||
"remove" => remove(&rt),
|
"remove" => remove(&rt),
|
||||||
_ => {
|
other => {
|
||||||
debug!("Unknown command"); // More error handling
|
debug!("Unknown command");
|
||||||
|
let _ = rt.handle_unknown_subcommand("imag-ref", other, rt.cli())
|
||||||
|
.map_err_trace_exit_unwrap(1)
|
||||||
|
.code()
|
||||||
|
.map(::std::process::exit);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -50,6 +50,7 @@ extern crate libimagutil;
|
||||||
extern crate libimagutil;
|
extern crate libimagutil;
|
||||||
|
|
||||||
use libimagrt::setup::generate_runtime_setup;
|
use libimagrt::setup::generate_runtime_setup;
|
||||||
|
use libimagerror::trace::MapErrTrace;
|
||||||
|
|
||||||
mod create;
|
mod create;
|
||||||
mod delete;
|
mod delete;
|
||||||
|
@ -92,9 +93,12 @@ fn main() {
|
||||||
"update" => update(&rt),
|
"update" => update(&rt),
|
||||||
"verify" => verify(&rt),
|
"verify" => verify(&rt),
|
||||||
"dump" => dump(&mut rt),
|
"dump" => dump(&mut rt),
|
||||||
_ => {
|
other => {
|
||||||
debug!("Unknown command");
|
debug!("Unknown command");
|
||||||
// More error handling
|
let _ = rt.handle_unknown_subcommand("imag-store", other, rt.cli())
|
||||||
|
.map_err_trace_exit_unwrap(1)
|
||||||
|
.code()
|
||||||
|
.map(std::process::exit);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -86,9 +86,12 @@ fn main() {
|
||||||
debug!("id = {:?}, add = {:?}, rem = {:?}", id, add, rem);
|
debug!("id = {:?}, add = {:?}, rem = {:?}", id, add, rem);
|
||||||
alter(&rt, id, add, rem);
|
alter(&rt, id, add, rem);
|
||||||
},
|
},
|
||||||
_ => {
|
other => {
|
||||||
error!("Unknown command");
|
debug!("Unknown command");
|
||||||
::std::process::exit(1)
|
let _ = rt.handle_unknown_subcommand("imag-tag", other, rt.cli())
|
||||||
|
.map_err_trace_exit_unwrap(1)
|
||||||
|
.code()
|
||||||
|
.map(std::process::exit);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,8 +77,12 @@ fn main() {
|
||||||
"collection" => collection(&rt),
|
"collection" => collection(&rt),
|
||||||
"list" => list(&rt),
|
"list" => list(&rt),
|
||||||
"remove" => remove(&rt),
|
"remove" => remove(&rt),
|
||||||
_ => {
|
other => {
|
||||||
debug!("Unknown command"); // More error handling
|
debug!("Unknown command");
|
||||||
|
let _ = rt.handle_unknown_subcommand("imag-bookmark", other, rt.cli())
|
||||||
|
.map_err_trace_exit_unwrap(1)
|
||||||
|
.code()
|
||||||
|
.map(::std::process::exit);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -102,8 +102,12 @@ fn main() {
|
||||||
"show" => show(&rt),
|
"show" => show(&rt),
|
||||||
"find" => find(&rt),
|
"find" => find(&rt),
|
||||||
"create" => create(&rt),
|
"create" => create(&rt),
|
||||||
_ => {
|
other => {
|
||||||
error!("Unknown command"); // More error handling
|
debug!("Unknown command");
|
||||||
|
let _ = rt.handle_unknown_subcommand("imag-contact", other, rt.cli())
|
||||||
|
.map_err_trace_exit_unwrap(1)
|
||||||
|
.code()
|
||||||
|
.map(::std::process::exit);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -48,6 +48,7 @@ extern crate libimagtimeui;
|
||||||
extern crate libimagutil;
|
extern crate libimagutil;
|
||||||
|
|
||||||
use libimagrt::setup::generate_runtime_setup;
|
use libimagrt::setup::generate_runtime_setup;
|
||||||
|
use libimagerror::trace::MapErrTrace;
|
||||||
|
|
||||||
mod create;
|
mod create;
|
||||||
mod delete;
|
mod delete;
|
||||||
|
@ -80,8 +81,12 @@ fn main() {
|
||||||
"edit" => edit(&rt),
|
"edit" => edit(&rt),
|
||||||
"list" => list(&rt),
|
"list" => list(&rt),
|
||||||
"view" => view(&rt),
|
"view" => view(&rt),
|
||||||
_ => {
|
other => {
|
||||||
debug!("Unknown command"); // More error handling
|
debug!("Unknown command");
|
||||||
|
let _ = rt.handle_unknown_subcommand("imag-diary", other, rt.cli())
|
||||||
|
.map_err_trace_exit_unwrap(1)
|
||||||
|
.code()
|
||||||
|
.map(std::process::exit);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -90,9 +90,12 @@ fn main() {
|
||||||
"status" => today(&rt, true),
|
"status" => today(&rt, true),
|
||||||
"show" => show(&rt),
|
"show" => show(&rt),
|
||||||
"done" => done(&rt),
|
"done" => done(&rt),
|
||||||
_ => {
|
other => {
|
||||||
debug!("Unknown command"); // More error handling
|
debug!("Unknown command");
|
||||||
exit(1)
|
let _ = rt.handle_unknown_subcommand("imag-habit", other, rt.cli())
|
||||||
|
.map_err_trace_exit_unwrap(1)
|
||||||
|
.code()
|
||||||
|
.map(::std::process::exit);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -72,9 +72,12 @@ fn main() {
|
||||||
if let Some(scmd) = rt.cli() .subcommand_name() {
|
if let Some(scmd) = rt.cli() .subcommand_name() {
|
||||||
match scmd {
|
match scmd {
|
||||||
"show" => show(&rt),
|
"show" => show(&rt),
|
||||||
_ => {
|
other => {
|
||||||
error!("Unknown command");
|
debug!("Unknown command");
|
||||||
::std::process::exit(1)
|
let _ = rt.handle_unknown_subcommand("imag-log", other, rt.cli())
|
||||||
|
.map_err_trace_exit_unwrap(1)
|
||||||
|
.code()
|
||||||
|
.map(std::process::exit);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -54,7 +54,13 @@ fn main() {
|
||||||
"import-mail" => import_mail(&rt),
|
"import-mail" => import_mail(&rt),
|
||||||
"list" => list(&rt),
|
"list" => list(&rt),
|
||||||
"mail-store" => mail_store(&rt),
|
"mail-store" => mail_store(&rt),
|
||||||
_ => debug!("Unknown command") // More error handling
|
other => {
|
||||||
|
debug!("Unknown command");
|
||||||
|
let _ = rt.handle_unknown_subcommand("imag-mail", other, rt.cli())
|
||||||
|
.map_err_trace_exit_unwrap(1)
|
||||||
|
.code()
|
||||||
|
.map(std::process::exit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,8 +66,12 @@ fn main() {
|
||||||
"delete" => delete(&rt),
|
"delete" => delete(&rt),
|
||||||
"edit" => edit(&rt),
|
"edit" => edit(&rt),
|
||||||
"list" => list(&rt),
|
"list" => list(&rt),
|
||||||
_ => {
|
other => {
|
||||||
debug!("Unknown command"); // More error handling
|
debug!("Unknown command");
|
||||||
|
let _ = rt.handle_unknown_subcommand("imag-notes", other, rt.cli())
|
||||||
|
.map_err_trace_exit_unwrap(1)
|
||||||
|
.code()
|
||||||
|
.map(std::process::exit);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -56,6 +56,7 @@ use week::week;
|
||||||
use year::year;
|
use year::year;
|
||||||
|
|
||||||
use libimagrt::setup::generate_runtime_setup;
|
use libimagrt::setup::generate_runtime_setup;
|
||||||
|
use libimagerror::trace::MapErrTrace;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let version = make_imag_version!();
|
let version = make_imag_version!();
|
||||||
|
@ -77,9 +78,12 @@ fn main() {
|
||||||
"track" => track(&rt),
|
"track" => track(&rt),
|
||||||
"week" => week(&rt),
|
"week" => week(&rt),
|
||||||
"year" => year(&rt),
|
"year" => year(&rt),
|
||||||
_ => {
|
other => {
|
||||||
error!("Unknown command");
|
debug!("Unknown command");
|
||||||
1
|
rt.handle_unknown_subcommand("imag-timetrack", other, rt.cli())
|
||||||
|
.map_err_trace_exit_unwrap(1)
|
||||||
|
.code()
|
||||||
|
.unwrap_or(0)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -51,10 +51,16 @@ fn main() {
|
||||||
match rt.cli().subcommand_name() {
|
match rt.cli().subcommand_name() {
|
||||||
Some("tw-hook") => tw_hook(&rt),
|
Some("tw-hook") => tw_hook(&rt),
|
||||||
Some("list") => list(&rt),
|
Some("list") => list(&rt),
|
||||||
|
Some(other) => {
|
||||||
|
debug!("Unknown command");
|
||||||
|
let _ = rt.handle_unknown_subcommand("imag-todo", other, rt.cli())
|
||||||
|
.map_err_trace_exit_unwrap(1)
|
||||||
|
.code()
|
||||||
|
.map(std::process::exit);
|
||||||
|
}
|
||||||
None => {
|
None => {
|
||||||
warn!("No command");
|
warn!("No command");
|
||||||
},
|
},
|
||||||
_ => unreachable!(),
|
|
||||||
} // end match scmd
|
} // end match scmd
|
||||||
} // end main
|
} // end main
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,9 @@ This section contains the changelog from the last release to the next release.
|
||||||
commandline flag.
|
commandline flag.
|
||||||
* `imag-habit today --done` and `imag-habit status --done` was added for
|
* `imag-habit today --done` and `imag-habit status --done` was added for
|
||||||
showing habits which are already done.
|
showing habits which are already done.
|
||||||
|
* `libimagrt` allows external subcommands now in the default clap app
|
||||||
|
builder helper. It also provides a helper for handling unknown
|
||||||
|
subcommands: `Runtime::handle_unknown_subcommand()`. See docs for details.
|
||||||
* Minor changes
|
* Minor changes
|
||||||
* A license-checker was included into the CI setup, which checks whether all
|
* A license-checker was included into the CI setup, which checks whether all
|
||||||
".rs"-files have the license header at the top of the file
|
".rs"-files have the license header at the top of the file
|
||||||
|
|
|
@ -24,6 +24,7 @@ use std::process::exit;
|
||||||
use std::io::Stdin;
|
use std::io::Stdin;
|
||||||
|
|
||||||
pub use clap::App;
|
pub use clap::App;
|
||||||
|
use clap::AppSettings;
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
use toml_query::read::TomlValueReadExt;
|
use toml_query::read::TomlValueReadExt;
|
||||||
|
|
||||||
|
@ -189,6 +190,7 @@ impl<'a> Runtime<'a> {
|
||||||
.version(version)
|
.version(version)
|
||||||
.author("Matthias Beyer <mail@beyermatthias.de>")
|
.author("Matthias Beyer <mail@beyermatthias.de>")
|
||||||
.about(about)
|
.about(about)
|
||||||
|
.settings(&[AppSettings::AllowExternalSubcommands])
|
||||||
.arg(Arg::with_name(Runtime::arg_verbosity_name())
|
.arg(Arg::with_name(Runtime::arg_verbosity_name())
|
||||||
.short("v")
|
.short("v")
|
||||||
.long("verbose")
|
.long("verbose")
|
||||||
|
@ -502,6 +504,81 @@ impl<'a> Runtime<'a> {
|
||||||
Some(::std::io::stdin())
|
Some(::std::io::stdin())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper for handling subcommands which are not available.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// For example someone calls `imag foo bar`. If `imag-foo` is in the $PATH, but it has no
|
||||||
|
/// subcommand `bar`, the `imag-foo` binary is able to automatically forward the invokation to a
|
||||||
|
/// `imag-foo-bar` binary which might be in $PATH.
|
||||||
|
///
|
||||||
|
/// It needs to call `Runtime::handle_unknown_subcommand` with the following parameters:
|
||||||
|
///
|
||||||
|
/// 1. The "command" which was issued. In the example this would be `"imag-foo"`
|
||||||
|
/// 2. The "subcommand" which is missing: `"bar"` in the example
|
||||||
|
/// 3. The `ArgMatches` object from the call, so that this routine can forward all flags passed
|
||||||
|
/// to the `bar` subcommand.
|
||||||
|
///
|
||||||
|
/// # Return value
|
||||||
|
///
|
||||||
|
/// On success, the exit status object of the `Command` invocation is returned.
|
||||||
|
/// On Error, a RuntimeError object is returned.
|
||||||
|
///
|
||||||
|
/// # Details
|
||||||
|
///
|
||||||
|
/// The `IMAG_RTP` variable is set for the child process. It is set to the current runtime path.
|
||||||
|
///
|
||||||
|
/// Stdin, stdout and stderr are inherited to the child process.
|
||||||
|
///
|
||||||
|
/// This function **blocks** until the child returns.
|
||||||
|
///
|
||||||
|
pub fn handle_unknown_subcommand<S: AsRef<str>>(&self,
|
||||||
|
command: S,
|
||||||
|
subcommand: S,
|
||||||
|
args: &ArgMatches)
|
||||||
|
-> Result<::std::process::ExitStatus, RuntimeError>
|
||||||
|
{
|
||||||
|
use std::io::Write;
|
||||||
|
use std::io::ErrorKind;
|
||||||
|
|
||||||
|
let rtp_str = self.rtp()
|
||||||
|
.to_str()
|
||||||
|
.map(String::from)
|
||||||
|
.ok_or(RuntimeErrorKind::IOError)
|
||||||
|
.map_err(RuntimeError::from_kind)?;
|
||||||
|
|
||||||
|
let command = format!("{}-{}", command.as_ref(), subcommand.as_ref());
|
||||||
|
|
||||||
|
let subcommand_args = args.values_of("")
|
||||||
|
.map(|sx| sx.map(String::from).collect())
|
||||||
|
.unwrap_or_else(|| vec![]);
|
||||||
|
|
||||||
|
Command::new(&command)
|
||||||
|
.stdin(::std::process::Stdio::inherit())
|
||||||
|
.stdout(::std::process::Stdio::inherit())
|
||||||
|
.stderr(::std::process::Stdio::inherit())
|
||||||
|
.args(&subcommand_args[..])
|
||||||
|
.env("IMAG_RTP", rtp_str)
|
||||||
|
.spawn()
|
||||||
|
.and_then(|mut c| c.wait())
|
||||||
|
.map_err(|e| match e.kind() {
|
||||||
|
ErrorKind::NotFound => {
|
||||||
|
let mut out = self.stdout();
|
||||||
|
|
||||||
|
if let Err(e) = writeln!(out, "No such command: '{}'", command) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
if let Err(e) = writeln!(out, "See 'imag --help' for available subcommands") {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
e
|
||||||
|
},
|
||||||
|
_ => e,
|
||||||
|
})
|
||||||
|
.map_err(RuntimeError::from)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Exported for the `imag` command, you probably do not want to use that.
|
/// Exported for the `imag` command, you probably do not want to use that.
|
||||||
|
|
Loading…
Reference in a new issue