summaryrefslogtreecommitdiffstats
path: root/lib/core
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2018-09-29 17:14:37 +0200
committerMatthias Beyer <mail@beyermatthias.de>2018-11-06 20:33:30 +0100
commitc1c74973e39814cda66f09f56d4132aed3bebc35 (patch)
treef362b3f062123c9510a607802b2fbd28f275e8d0 /lib/core
parentdb4e83f18f032b531b09e59f75d857541cdea919 (diff)
Implement ID providing in libimagrt
With this patch, IDs can be fetched from the CLI via libimagrt. This gives us the possibility to automatically handle "stdin provides IDs" in libimagrt with less boilerplate in the binaries codebases. Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
Diffstat (limited to 'lib/core')
-rw-r--r--lib/core/libimagrt/src/runtime.rs78
1 files changed, 74 insertions, 4 deletions
diff --git a/lib/core/libimagrt/src/runtime.rs b/lib/core/libimagrt/src/runtime.rs
index e00a93f6..ab0b398c 100644
--- a/lib/core/libimagrt/src/runtime.rs
+++ b/lib/core/libimagrt/src/runtime.rs
@@ -144,14 +144,20 @@ impl<'a> Runtime<'a> {
Store::new(storepath, &config)
};
+ let has_output_pipe = !atty::is(atty::Stream::Stdout);
+ let has_input_pipe = !atty::is(atty::Stream::Stdin);
+
+ debug!("has output pipe = {}", has_output_pipe);
+ debug!("has input pipe = {}", has_input_pipe);
+
store_result.map(|store| Runtime {
cli_matches: matches,
configuration: config,
rtp: rtp,
store: store,
- has_output_pipe: !atty::is(atty::Stream::Stdout),
- has_input_pipe: !atty::is(atty::Stream::Stdin),
+ has_output_pipe,
+ has_input_pipe,
})
.context(err_msg("Cannot instantiate runtime"))
.map_err(Error::from)
@@ -383,6 +389,33 @@ impl<'a> Runtime<'a> {
&self.cli_matches
}
+ pub fn ids_from_stdin(&self) -> bool {
+ self.has_input_pipe
+ }
+
+ pub fn ids<T: IdPathProvider>(&self) -> Result<Vec<StoreId>> {
+ use std::io::Read;
+
+ if self.has_input_pipe {
+ trace!("Getting IDs from stdin...");
+ let stdin = ::std::io::stdin();
+ let mut lock = stdin.lock();
+
+ let mut buf = String::new();
+ lock.read_to_string(&mut buf)
+ .map_err(Error::from)
+ .and_then(|_| {
+ trace!("Got IDs = {}", buf);
+ buf.lines()
+ .map(PathBuf::from)
+ .map(|id| StoreId::new_baseless(id).map_err(Error::from))
+ .collect()
+ })
+ } else {
+ Ok(T::get_ids(self.cli()))
+ }
+ }
+
/// Get the configuration object
pub fn config(&self) -> Option<&Value> {
self.configuration.as_ref()
@@ -424,8 +457,12 @@ impl<'a> Runtime<'a> {
})
}
+ pub fn output_is_pipe(&self) -> bool {
+ self.has_output_pipe
+ }
+
pub fn stdout(&self) -> OutputProxy {
- if self.has_output_pipe {
+ if self.output_is_pipe() {
OutputProxy::Err(::std::io::stderr())
} else {
OutputProxy::Out(::std::io::stdout())
@@ -548,7 +585,8 @@ impl<'a> Runtime<'a> {
fn report_touched_id(&self, id: &StoreId, output: &mut StdoutLock) -> Result<()> {
use std::io::Write;
- if self.has_output_pipe {
+ if self.output_is_pipe() {
+ trace!("Reporting: {} to {:?}", id, output);
writeln!(output, "{}", id)?;
}
@@ -556,6 +594,38 @@ impl<'a> Runtime<'a> {
}
}
+/// A trait for the path provider functionality
+///
+/// This trait can be implement on a type so that it can provide IDs when given a ArgMatches
+/// object.
+///
+/// It can be used with Runtime::ids() and libimagrt handles "stdin-provides-ids" cases
+/// automatically:
+///
+/// ```ignore
+/// runtime.ids::<PathProvider>()?.iter().for_each(|id| /* ... */)
+/// ```
+///
+/// libimagrt does not call the PathProvider if the ids are provided by piping to stdin.
+///
+///
+/// # Passed arguments
+///
+/// The arguments which are passed into the IdPathProvider::get_ids() function are the _top level
+/// ArgMatches_. Traversing might be required in the implementation of the ::get_ids() function.
+///
+///
+/// # Returns
+///
+/// In case of error, the IdPathProvider::get_ids() function should exit the application
+/// with the appropriate error message(s).
+///
+/// On success, the StoreId objects to operate on are returned from the ArgMatches.
+///
+pub trait IdPathProvider {
+ fn get_ids(matches: &ArgMatches) -> Vec<StoreId>;
+}
+
/// Exported for the `imag` command, you probably do not want to use that.
pub fn get_rtp_match<'a>(matches: &ArgMatches<'a>) -> PathBuf {
use std::env;