Implement ID reporting

This patch adds the id reporting feature to libimagrt::runtime::Runtime,
where processed ("touched") ids can be reported to the Runtime and then
get printed to stdout if stdout is a pipe.

Other output is automatically redirected to stderr if stdout is a pipe
now.
This commit is contained in:
Matthias Beyer 2018-09-27 14:19:55 +02:00
parent 8552843796
commit db4e83f18f

View file

@ -23,6 +23,8 @@ use std::env;
use std::process::exit; use std::process::exit;
use std::io::Stdin; use std::io::Stdin;
use std::sync::Arc; use std::sync::Arc;
use std::io::StdoutLock;
use std::borrow::Borrow;
pub use clap::App; pub use clap::App;
use clap::AppSettings; use clap::AppSettings;
@ -42,9 +44,11 @@ use io::OutputProxy;
use libimagerror::errors::ErrorMsg as EM; use libimagerror::errors::ErrorMsg as EM;
use libimagerror::trace::*; use libimagerror::trace::*;
use libimagstore::store::Store; use libimagstore::store::Store;
use libimagstore::storeid::StoreId;
use libimagstore::file_abstraction::InMemoryFileAbstraction; use libimagstore::file_abstraction::InMemoryFileAbstraction;
use libimagutil::debug_result::DebugResult; use libimagutil::debug_result::DebugResult;
use spec::CliSpec; use spec::CliSpec;
use atty;
/// The Runtime object /// The Runtime object
/// ///
@ -55,6 +59,9 @@ pub struct Runtime<'a> {
configuration: Option<Value>, configuration: Option<Value>,
cli_matches: ArgMatches<'a>, cli_matches: ArgMatches<'a>,
store: Store, store: Store,
has_output_pipe: bool,
has_input_pipe: bool,
} }
impl<'a> Runtime<'a> { impl<'a> Runtime<'a> {
@ -142,6 +149,9 @@ impl<'a> Runtime<'a> {
configuration: config, configuration: config,
rtp: rtp, rtp: rtp,
store: store, store: store,
has_output_pipe: !atty::is(atty::Stream::Stdout),
has_input_pipe: !atty::is(atty::Stream::Stdin),
}) })
.context(err_msg("Cannot instantiate runtime")) .context(err_msg("Cannot instantiate runtime"))
.map_err(Error::from) .map_err(Error::from)
@ -415,16 +425,24 @@ impl<'a> Runtime<'a> {
} }
pub fn stdout(&self) -> OutputProxy { pub fn stdout(&self) -> OutputProxy {
if self.has_output_pipe {
OutputProxy::Err(::std::io::stderr())
} else {
OutputProxy::Out(::std::io::stdout()) OutputProxy::Out(::std::io::stdout())
} }
}
pub fn stderr(&self) -> OutputProxy { pub fn stderr(&self) -> OutputProxy {
OutputProxy::Err(::std::io::stderr()) OutputProxy::Err(::std::io::stderr())
} }
pub fn stdin(&self) -> Option<Stdin> { pub fn stdin(&self) -> Option<Stdin> {
if self.has_input_pipe {
None
} else {
Some(::std::io::stdin()) Some(::std::io::stdin())
} }
}
/// Helper for handling subcommands which are not available. /// Helper for handling subcommands which are not available.
/// ///
@ -504,6 +522,38 @@ impl<'a> Runtime<'a> {
.context(EM::IO) .context(EM::IO)
.map_err(Error::from) .map_err(Error::from)
} }
pub fn report_touched(&self, id: &StoreId) -> Result<()> {
let out = ::std::io::stdout();
let mut lock = out.lock();
self.report_touched_id(id, &mut lock)
}
pub fn report_all_touched<ID, I>(&self, ids: I) -> Result<()>
where ID: Borrow<StoreId> + Sized,
I: Iterator<Item = ID>
{
let out = ::std::io::stdout();
let mut lock = out.lock();
for id in ids {
self.report_touched_id(id.borrow(), &mut lock)?;
}
Ok(())
}
#[inline]
fn report_touched_id(&self, id: &StoreId, output: &mut StdoutLock) -> Result<()> {
use std::io::Write;
if self.has_output_pipe {
writeln!(output, "{}", id)?;
}
Ok(())
}
} }
/// 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.