Merge branch 'imag-tag/filtering' into master
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
This commit is contained in:
commit
1a25bd2da4
3 changed files with 175 additions and 38 deletions
|
@ -66,10 +66,12 @@ use failure::Error;
|
|||
use failure::err_msg;
|
||||
use resiter::AndThen;
|
||||
use resiter::Map;
|
||||
use resiter::FilterMap;
|
||||
|
||||
use libimagrt::runtime::Runtime;
|
||||
use libimagrt::application::ImagApplication;
|
||||
use libimagentrytag::tagable::Tagable;
|
||||
use libimagentrytag::tag::is_tag_str;
|
||||
use libimagentrytag::tag::Tag;
|
||||
use libimagstore::storeid::StoreId;
|
||||
|
||||
|
@ -86,51 +88,118 @@ pub enum ImagTag {}
|
|||
impl ImagApplication for ImagTag {
|
||||
fn run(rt: Runtime) -> Result<()> {
|
||||
let process = |iter: &mut dyn Iterator<Item = Result<StoreId>>| -> Result<()> {
|
||||
if let Some(name) = rt.cli().subcommand_name() {
|
||||
match name {
|
||||
"list" => iter
|
||||
.map_ok(|id| list(id, &rt))
|
||||
match rt.cli().subcommand() {
|
||||
("list", _) => iter
|
||||
.map_ok(|id| list(id, &rt))
|
||||
.collect::<Result<Vec<_>>>()
|
||||
.map(|_| ()),
|
||||
|
||||
("remove", _) => iter.and_then_ok(|id| {
|
||||
let add = None;
|
||||
let rem = get_remove_tags(rt.cli())?;
|
||||
debug!("id = {:?}, add = {:?}, rem = {:?}", id, add, rem);
|
||||
alter(&rt, id, add, rem)
|
||||
}).collect(),
|
||||
|
||||
("add", _) => iter.and_then_ok(|id| {
|
||||
let add = get_add_tags(rt.cli())?;
|
||||
let rem = None;
|
||||
debug!("id = {:?}, add = {:?}, rem = {:?}", id, add, rem);
|
||||
alter(&rt, id, add, rem)
|
||||
}).collect(),
|
||||
|
||||
("present", Some(scmd)) => {
|
||||
let must_be_present = scmd
|
||||
.values_of("present-tag")
|
||||
.unwrap()
|
||||
.map(String::from)
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
must_be_present.iter().map(|t| is_tag_str(t)).collect::<Result<Vec<_>>>()?;
|
||||
|
||||
iter.filter_map_ok(|id| {
|
||||
match rt.store().get(id.clone()) {
|
||||
Err(e) => Some(Err(e)),
|
||||
Ok(None) => Some(Err(format_err!("No entry for id {}", id))),
|
||||
Ok(Some(entry)) => {
|
||||
let entry_tags = match entry.get_tags() {
|
||||
Err(e) => return Some(Err(e)),
|
||||
Ok(e) => e,
|
||||
};
|
||||
|
||||
if must_be_present.iter().all(|pres| entry_tags.contains(pres)) {
|
||||
Some(Ok(entry))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.and_then_ok(|e| {
|
||||
if !rt.output_is_pipe() {
|
||||
writeln!(rt.stdout(), "{}", e.get_location())?;
|
||||
}
|
||||
Ok(e)
|
||||
})
|
||||
.and_then_ok(|e| rt.report_touched(e.get_location()).map_err(Error::from))
|
||||
.collect::<Result<Vec<_>>>()
|
||||
.map(|_| ()),
|
||||
.map(|_| ())
|
||||
},
|
||||
|
||||
"remove" => iter.and_then_ok(|id| {
|
||||
let add = None;
|
||||
let rem = get_remove_tags(rt.cli())?;
|
||||
debug!("id = {:?}, add = {:?}, rem = {:?}", id, add, rem);
|
||||
alter(&rt, id, add, rem)
|
||||
}).collect(),
|
||||
("missing", Some(scmd)) => {
|
||||
let must_be_missing = scmd
|
||||
.values_of("missing-tag")
|
||||
.unwrap()
|
||||
.map(String::from)
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
"add" => iter.and_then_ok(|id| {
|
||||
let add = get_add_tags(rt.cli())?;
|
||||
let rem = None;
|
||||
debug!("id = {:?}, add = {:?}, rem = {:?}", id, add, rem);
|
||||
alter(&rt, id, add, rem)
|
||||
}).collect(),
|
||||
must_be_missing.iter().map(|t| is_tag_str(t)).collect::<Result<Vec<_>>>()?;
|
||||
|
||||
other => {
|
||||
debug!("Unknown command");
|
||||
if rt.handle_unknown_subcommand("imag-tag", other, rt.cli())?.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format_err!("Subcommand failed"))
|
||||
}
|
||||
},
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
iter.filter_map_ok(|id| {
|
||||
match rt.store().get(id.clone()) {
|
||||
Err(e) => Some(Err(e)),
|
||||
Ok(None) => Some(Err(format_err!("No entry for id {}", id))),
|
||||
Ok(Some(entry)) => {
|
||||
let entry_tags = match entry.get_tags() {
|
||||
Err(e) => return Some(Err(e)),
|
||||
Ok(e) => e,
|
||||
};
|
||||
|
||||
if must_be_missing.iter().all(|miss| !entry_tags.contains(miss)) {
|
||||
Some(Ok(entry))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.and_then_ok(|e| {
|
||||
if !rt.output_is_pipe() {
|
||||
writeln!(rt.stdout(), "{}", e.get_location())?;
|
||||
}
|
||||
Ok(e)
|
||||
})
|
||||
.and_then_ok(|e| rt.report_touched(e.get_location()).map_err(Error::from))
|
||||
.collect::<Result<Vec<_>>>()
|
||||
.map(|_| ())
|
||||
},
|
||||
|
||||
(other, _) => {
|
||||
debug!("Unknown command");
|
||||
if rt.handle_unknown_subcommand("imag-tag", other, rt.cli())?.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format_err!("Subcommand failed"))
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
if rt.ids_from_stdin() {
|
||||
debug!("Fetching IDs from stdin...");
|
||||
let mut iter = rt.ids::<crate::ui::PathProvider>()?
|
||||
.ok_or_else(|| err_msg("No ids supplied"))?
|
||||
.into_iter()
|
||||
.map(Ok);
|
||||
|
||||
process(&mut iter)
|
||||
} else {
|
||||
process(&mut rt.store().entries()?)
|
||||
match rt.ids::<crate::ui::PathProvider>()? {
|
||||
Some(ids) => process(&mut ids.into_iter().map(Ok)),
|
||||
None => process(&mut rt.store().entries()?),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -101,6 +101,26 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
|||
.required(true))
|
||||
)
|
||||
|
||||
.subcommand(SubCommand::with_name("present")
|
||||
.about("List entries that have a certain tag")
|
||||
.version("0.1")
|
||||
.arg(Arg::with_name("present-tag")
|
||||
.index(1)
|
||||
.required(true)
|
||||
.multiple(true)
|
||||
.help("Tag to list entries for"))
|
||||
)
|
||||
|
||||
.subcommand(SubCommand::with_name("missing")
|
||||
.about("List entries miss a certain tag")
|
||||
.version("0.1")
|
||||
.arg(Arg::with_name("missing-tag")
|
||||
.index(1)
|
||||
.required(true)
|
||||
.multiple(true)
|
||||
.help("Tag which should be missing in the entries"))
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
pub struct PathProvider;
|
||||
|
|
|
@ -34,6 +34,14 @@ pub fn call(tmpdir: &TempDir, args: &[&str]) -> Vec<String> {
|
|||
crate::imag::stdout_of_command(binary)
|
||||
}
|
||||
|
||||
pub fn call_give_ids(tmpdir: &TempDir, args: &[&str]) -> Vec<String> {
|
||||
let mut binary = binary(tmpdir);
|
||||
binary.stdin(std::process::Stdio::inherit());
|
||||
binary.args(args);
|
||||
debug!("Command = {:?}", binary);
|
||||
crate::imag::stdout_of_command(binary)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_entry_has_no_tags() {
|
||||
crate::setup_logging();
|
||||
|
@ -94,3 +102,43 @@ fn test_adding_twice_does_not_add_twice() {
|
|||
assert_eq!(output[0], "tag");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_listing_entries_with_certain_tag() {
|
||||
crate::setup_logging();
|
||||
let imag_home = crate::imag::make_temphome();
|
||||
crate::imag_init::call(&imag_home);
|
||||
crate::imag_create::call(&imag_home, &["test1", "test2", "test3"]);
|
||||
let _ = call(&imag_home, &["test1", "add", "tag1"]);
|
||||
let _ = call(&imag_home, &["test2", "add", "tag2"]);
|
||||
let _ = call(&imag_home, &["test3", "add", "tag3"]);
|
||||
|
||||
let output = call_give_ids(&imag_home, &["present", "tag1"]);
|
||||
debug!("output = {:?}", output);
|
||||
|
||||
assert!(!output.is_empty());
|
||||
assert_eq!(output.len(), 1);
|
||||
assert!(output[0].contains("test1"));
|
||||
assert!(output.iter().all(|s| !s.contains("test2")));
|
||||
assert!(output.iter().all(|s| !s.contains("test3")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_listing_entries_without_certain_tag() {
|
||||
crate::setup_logging();
|
||||
let imag_home = crate::imag::make_temphome();
|
||||
crate::imag_init::call(&imag_home);
|
||||
crate::imag_create::call(&imag_home, &["test1", "test2", "test3"]);
|
||||
let _ = call(&imag_home, &["test1", "add", "tag1"]);
|
||||
let _ = call(&imag_home, &["test2", "add", "tag2"]);
|
||||
let _ = call(&imag_home, &["test3", "add", "tag3"]);
|
||||
|
||||
let output = call_give_ids(&imag_home, &["missing", "tag1"]);
|
||||
debug!("output = {:?}", output);
|
||||
|
||||
assert!(!output.is_empty());
|
||||
assert_eq!(output.len(), 2);
|
||||
assert!(output.iter().any(|s| s.contains("test2")));
|
||||
assert!(output.iter().any(|s| s.contains("test3")));
|
||||
assert!(output.iter().all(|s| !s.contains("test1")));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue