summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2018-04-05 09:36:31 +0200
committerGitHub <noreply@github.com>2018-04-05 09:36:31 +0200
commit8492f149be4f452b015f0681b1ece50781878057 (patch)
tree1daaf007c06fde2d554ac0dd69e6ba52eab191e0
parent348389f7453b47e407c3c4d25d8bf8e970900b1d (diff)
parent8c1b4124c0261f9e131747f730c4ced4dc1257a6 (diff)
downloadimag-8492f149be4f452b015f0681b1ece50781878057.zip
imag-8492f149be4f452b015f0681b1ece50781878057.tar.gz
Merge pull request #1373 from matthiasbeyer/libimagrt/handle-unknown-subcommand
libimagrt: Handle unknown subcommand
-rw-r--r--bin/core/imag-annotate/src/main.rs9
-rw-r--r--bin/core/imag-gps/src/main.rs9
-rw-r--r--bin/core/imag-link/src/main.rs8
-rw-r--r--bin/core/imag-ref/src/main.rs8
-rw-r--r--bin/core/imag-store/src/main.rs8
-rw-r--r--bin/core/imag-tag/src/main.rs9
-rw-r--r--bin/domain/imag-bookmark/src/main.rs8
-rw-r--r--bin/domain/imag-contact/src/main.rs8
-rw-r--r--bin/domain/imag-diary/src/main.rs9
-rw-r--r--bin/domain/imag-habit/src/main.rs9
-rw-r--r--bin/domain/imag-log/src/main.rs9
-rw-r--r--bin/domain/imag-mail/src/main.rs8
-rw-r--r--bin/domain/imag-notes/src/main.rs8
-rw-r--r--bin/domain/imag-timetrack/src/main.rs10
-rw-r--r--bin/domain/imag-todo/src/main.rs8
-rw-r--r--doc/src/09020-changelog.md3
-rw-r--r--lib/core/libimagrt/src/runtime.rs77
17 files changed, 177 insertions, 31 deletions
diff --git a/bin/core/imag-annotate/src/main.rs b/bin/core/imag-annotate/src/main.rs
index 790ce8f..d196c7c 100644
--- a/bin/core/imag-annotate/src/main.rs
+++ b/bin/core/imag-annotate/src/main.rs
@@ -57,7 +57,6 @@ use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup;
use libimagstore::store::FileLockEntry;
use libimagstore::storeid::IntoStoreId;
-use libimagutil::warn_exit::warn_exit;
mod ui;
@@ -75,7 +74,13 @@ fn main() {
"add" => add(&rt),
"remove" => remove(&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);
+ },
}
});
}
diff --git a/bin/core/imag-gps/src/main.rs b/bin/core/imag-gps/src/main.rs
index 3277547..502497a 100644
--- a/bin/core/imag-gps/src/main.rs
+++ b/bin/core/imag-gps/src/main.rs
@@ -53,7 +53,6 @@ use libimagentrygps::types::*;
use libimagentrygps::entry::*;
use libimagrt::setup::generate_runtime_setup;
use libimagrt::runtime::Runtime;
-use libimagutil::warn_exit::warn_exit;
use libimagerror::trace::MapErrTrace;
use libimagerror::exit::ExitUnwrap;
use libimagerror::io::ToExitCode;
@@ -75,7 +74,13 @@ fn main() {
"add" => add(&rt),
"remove" => remove(&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);
+ }
}
});
}
diff --git a/bin/core/imag-link/src/main.rs b/bin/core/imag-link/src/main.rs
index bc6af04..4dd8e0d 100644
--- a/bin/core/imag-link/src/main.rs
+++ b/bin/core/imag-link/src/main.rs
@@ -104,7 +104,13 @@ fn main() {
"remove" => remove_linking(&rt),
"unlink" => unlink(&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(|| {
diff --git a/bin/core/imag-ref/src/main.rs b/bin/core/imag-ref/src/main.rs
index d806ff9..96dedad 100644
--- a/bin/core/imag-ref/src/main.rs
+++ b/bin/core/imag-ref/src/main.rs
@@ -67,8 +67,12 @@ fn main() {
match name {
"deref" => deref(&rt),
"remove" => remove(&rt),
- _ => {
- debug!("Unknown command"); // More error handling
+ other => {
+ debug!("Unknown command");
+ let _ = rt.handle_unknown_subcommand("imag-ref", other, rt.cli())
+ .map_err_trace_exit_unwrap(1)
+ .code()
+ .map(::std::process::exit);
},
};
});
diff --git a/bin/core/imag-store/src/main.rs b/bin/core/imag-store/src/main.rs
index 60f80d1..5ec16ce 100644
--- a/bin/core/imag-store/src/main.rs
+++ b/bin/core/imag-store/src/main.rs
@@ -50,6 +50,7 @@ extern crate libimagutil;
extern crate libimagutil;
use libimagrt::setup::generate_runtime_setup;
+use libimagerror::trace::MapErrTrace;
mod create;
mod delete;
@@ -92,9 +93,12 @@ fn main() {
"update" => update(&rt),
"verify" => verify(&rt),
"dump" => dump(&mut rt),
- _ => {
+ other => {
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 {
diff --git a/bin/core/imag-tag/src/main.rs b/bin/core/imag-tag/src/main.rs
index 39f468a..200456c 100644
--- a/bin/core/imag-tag/src/main.rs
+++ b/bin/core/imag-tag/src/main.rs
@@ -86,9 +86,12 @@ fn main() {
debug!("id = {:?}, add = {:?}, rem = {:?}", id, add, rem);
alter(&rt, id, add, rem);
},
- _ => {
- error!("Unknown command");
- ::std::process::exit(1)
+ other => {
+ debug!("Unknown command");
+ let _ = rt.handle_unknown_subcommand("imag-tag", other, rt.cli())
+ .map_err_trace_exit_unwrap(1)
+ .code()
+ .map(std::process::exit);
},
});
}
diff --git a/bin/domain/imag-bookmark/src/main.rs b/bin/domain/imag-bookmark/src/main.rs
index 48f349c..3438ee7 100644
--- a/bin/domain/imag-bookmark/src/main.rs
+++ b/bin/domain/imag-bookmark/src/main.rs
@@ -77,8 +77,12 @@ fn main() {
"collection" => collection(&rt),
"list" => list(&rt),
"remove" => remove(&rt),
- _ => {
- debug!("Unknown command"); // More error handling
+ other => {
+ debug!("Unknown command");
+ let _ = rt.handle_unknown_subcommand("imag-bookmark", other, rt.cli())
+ .map_err_trace_exit_unwrap(1)
+ .code()
+ .map(::std::process::exit);
},
}
});
diff --git a/bin/domain/imag-contact/src/main.rs b/bin/domain/imag-contact/src/main.rs
index 3c898d6..e8dda55 100644
--- a/bin/domain/imag-contact/src/main.rs
+++ b/bin/domain/imag-contact/src/main.rs
@@ -102,8 +102,12 @@ fn main() {
"show" => show(&rt),
"find" => find(&rt),
"create" => create(&rt),
- _ => {
- error!("Unknown command"); // More error handling
+ other => {
+ debug!("Unknown command");
+ let _ = rt.handle_unknown_subcommand("imag-contact", other, rt.cli())
+ .map_err_trace_exit_unwrap(1)
+ .code()
+ .map(::std::process::exit);
},
}
});
diff --git a/bin/domain/imag-diary/src/main.rs b/bin/domain/imag-diary/src/main.rs
index ccaf3ab..201f843 100644
--- a/bin/domain/imag-diary/src/main.rs
+++ b/bin/domain/imag-diary/src/main.rs
@@ -48,6 +48,7 @@ extern crate libimagtimeui;
extern crate libimagutil;
use libimagrt::setup::generate_runtime_setup;
+use libimagerror::trace::MapErrTrace;
mod create;
mod delete;
@@ -80,8 +81,12 @@ fn main() {
"edit" => edit(&rt),
"list" => list(&rt),
"view" => view(&rt),
- _ => {
- debug!("Unknown command"); // More error handling
+ other => {
+ debug!("Unknown command");
+ let _ = rt.handle_unknown_subcommand("imag-diary", other, rt.cli())
+ .map_err_trace_exit_unwrap(1)
+ .code()
+ .map(std::process::exit);
},
}
});
diff --git a/bin/domain/imag-habit/src/main.rs b/bin/domain/imag-habit/src/main.rs
index ccb8e71..61b69bd 100644
--- a/bin/domain/imag-habit/src/main.rs
+++ b/bin/domain/imag-habit/src/main.rs
@@ -90,9 +90,12 @@ fn main() {
"status" => today(&rt, true),
"show" => show(&rt),
"done" => done(&rt),
- _ => {
- debug!("Unknown command"); // More error handling
- exit(1)
+ other => {
+ debug!("Unknown command");
+ let _ = rt.handle_unknown_subcommand("imag-habit", other, rt.cli())
+ .map_err_trace_exit_unwrap(1)
+ .code()
+ .map(::std::process::exit);
},
}
})
diff --git a/bin/domain/imag-log/src/main.rs b/bin/domain/imag-log/src/main.rs
index 7c2804e..bc5a6a7 100644
--- a/bin/domain/imag-log/src/main.rs
+++ b/bin/domain/imag-log/src/main.rs
@@ -72,9 +72,12 @@ fn main() {
if let Some(scmd) = rt.cli() .subcommand_name() {
match scmd {
"show" => show(&rt),
- _ => {
- error!("Unknown command");
- ::std::process::exit(1)
+ other => {
+ debug!("Unknown command");
+ let _ = rt.handle_unknown_subcommand("imag-log", other, rt.cli())
+ .map_err_trace_exit_unwrap(1)
+ .code()
+ .map(std::process::exit);
},
}
} else {
diff --git a/bin/domain/imag-mail/src/main.rs b/bin/domain/imag-mail/src/main.rs
index a108d69..b7d67f8 100644
--- a/bin/domain/imag-mail/src/main.rs
+++ b/bin/domain/imag-mail/src/main.rs
@@ -54,7 +54,13 @@ fn main() {
"import-mail" => import_mail(&rt),
"list" => list(&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);
+ }
}
});
}
diff --git a/bin/domain/imag-notes/src/main.rs b/bin/domain/imag-notes/src/main.rs
index de395c5..6d193b4 100644
--- a/bin/domain/imag-notes/src/main.rs
+++ b/bin/domain/imag-notes/src/main.rs
@@ -66,8 +66,12 @@ fn main() {
"delete" => delete(&rt),
"edit" => edit(&rt),
"list" => list(&rt),
- _ => {
- debug!("Unknown command"); // More error handling
+ other => {
+ debug!("Unknown command");
+ let _ = rt.handle_unknown_subcommand("imag-notes", other, rt.cli())
+ .map_err_trace_exit_unwrap(1)
+ .code()
+ .map(std::process::exit);
},
};
});
diff --git a/bin/domain/imag-timetrack/src/main.rs b/bin/domain/imag-timetrack/src/main.rs
index ef857d5..2f43245 100644
--- a/bin/domain/imag-timetrack/src/main.rs
+++ b/bin/domain/imag-timetrack/src/main.rs
@@ -56,6 +56,7 @@ use week::week;
use year::year;
use libimagrt::setup::generate_runtime_setup;
+use libimagerror::trace::MapErrTrace;
fn main() {
let version = make_imag_version!();
@@ -77,9 +78,12 @@ fn main() {
"track" => track(&rt),
"week" => week(&rt),
"year" => year(&rt),
- _ => {
- error!("Unknown command");
- 1
+ other => {
+ debug!("Unknown command");
+ rt.handle_unknown_subcommand("imag-timetrack", other, rt.cli())
+ .map_err_trace_exit_unwrap(1)
+ .code()
+ .unwrap_or(0)
},
}
} else {
diff --git a/bin/domain/imag-todo/src/main.rs b/bin/domain/imag-todo/src/main.rs
index 7eaf1d8..22ae1ed 100644
--- a/bin/domain/imag-todo/src/main.rs
+++ b/bin/domain/imag-todo/src/main.rs
@@ -51,10 +51,16 @@ fn main() {
match rt.cli().subcommand_name() {
Some("tw-hook") => tw_hook(&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 => {
warn!("No command");
},
- _ => unreachable!(),
} // end match scmd
} // end main
diff --git a/doc/src/09020-changelog.md b/doc/src/09020-changelog.md
index 93d1634..f4b8642 100644
--- a/doc/src/09020-changelog.md
+++ b/doc/src/09020-changelog.md
@@ -45,6 +45,9 @@ This section contains the changelog from the last release to the next release.
commandline flag.
* `imag-habit today --done` and `imag-habit status --done` was added for
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
* 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
diff --git a/lib/core/libimagrt/src/runtime.rs b/lib/core/libimagrt/src/runtime.rs
index 8cb4521..07b24bd 100644
--- a/lib/core/libimagrt/src/runtime.rs
+++ b/lib/core/libimagrt/src/runtime.rs
@@ -24,6 +24,7 @@ use std::process::exit;
use std::io::Stdin;
pub use clap::App;
+use clap::AppSettings;
use toml::Value;
use toml_query::read::TomlValueReadExt;
@@ -189,6 +190,7 @@ impl<'a> Runtime<'a> {
.version(version)
.author("Matthias Beyer <mail@beyermatthias.de>")
.about(about)
+ .settings(&[AppSettings::AllowExternalSubcommands])
.arg(Arg::with_name(Runtime::arg_verbosity_name())
.short("v")
.long("verbose")
@@ -502,6 +504,81 @@ impl<'a> Runtime<'a> {
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.