Merge pull request #1343 from matthiasbeyer/imag-tag/rewrite-cli

imag-tag: rewrite cli
This commit is contained in:
Matthias Beyer 2018-03-12 23:07:06 +01:00 committed by GitHub
commit ee72e61b44
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 61 additions and 97 deletions

View file

@ -67,26 +67,29 @@ fn main() {
"Direct interface to the store. Use with great care!",
build_ui);
let id = rt.cli().value_of("id").unwrap(); // enforced by clap
let id = rt.cli().value_of("id").map(PathBuf::from).unwrap(); // enforced by clap
rt.cli()
.subcommand_name()
.map_or_else(
|| {
.map(|name| match name {
"list" => list(id, &rt),
"remove" => {
let id = PathBuf::from(id);
let add = get_add_tags(rt.cli());
let add = None;
let rem = get_remove_tags(rt.cli());
debug!("id = {:?}, add = {:?}, rem = {:?}", id, add, rem);
alter(&rt, id, add, rem);
},
|name| {
"add" => {
let id = PathBuf::from(id);
debug!("Call: {}", name);
match name {
"list" => list(id, &rt),
_ => {
warn!("Unknown command");
// More error handling
let add = get_add_tags(rt.cli());
let rem = None;
debug!("id = {:?}, add = {:?}, rem = {:?}", id, add, rem);
alter(&rt, id, add, rem);
},
_ => {
error!("Unknown command");
::std::process::exit(1)
},
};
});
}
@ -190,36 +193,28 @@ fn list(id: PathBuf, rt: &Runtime) {
///
/// Returns none if the argument was not specified
fn get_add_tags(matches: &ArgMatches) -> Option<Vec<Tag>> {
let a = "add-tags";
extract_tags(matches, a, '+')
.or_else(|| matches.values_of(a).map(|values| values.map(String::from).collect()))
retrieve_tags(matches, "add", "add-tags")
}
/// Get the tags which should be removed from the commandline
///
/// Returns none if the argument was not specified
fn get_remove_tags(matches: &ArgMatches) -> Option<Vec<Tag>> {
let r = "remove-tags";
extract_tags(matches, r, '+')
.or_else(|| matches.values_of(r).map(|values| values.map(String::from).collect()))
retrieve_tags(matches, "remove", "remove-tags")
}
fn extract_tags(matches: &ArgMatches, specifier: &str, specchar: char) -> Option<Vec<Tag>> {
if let Some(submatch) = matches.subcommand_matches("tags") {
submatch.values_of(specifier)
.map(|values| values.map(String::from).collect())
} else {
matches.values_of("specify-tags")
.map(|argmatches| {
argmatches
fn retrieve_tags(m: &ArgMatches, s: &'static str, v: &'static str) -> Option<Vec<Tag>> {
Some(m
.subcommand_matches(s)
.unwrap_or_else(|| {
error!("Expected subcommand '{}', but was not specified", s);
::std::process::exit(1)
})
.values_of(v)
.unwrap() // enforced by clap
.into_iter()
.map(String::from)
.filter(|s| s.starts_with(specchar))
.map(|s| {
String::from(s.split_at(1).1)
})
.collect()
})
}
.collect())
}
#[cfg(test)]
@ -275,7 +270,7 @@ mod tests {
setup_logging();
debug!("Generating runtime");
let name = "test-tag-add-adds-tags";
let rt = generate_test_runtime(vec![name, "--add", "foo"]).unwrap();
let rt = generate_test_runtime(vec![name, "add", "foo"]).unwrap();
debug!("Creating default entry");
create_test_default_entry(&rt, name).unwrap();
@ -285,12 +280,8 @@ mod tests {
let add = get_add_tags(rt.cli());
debug!("Add-tags: {:?}", add);
debug!("Getting 'remove' tags");
let rem = get_remove_tags(rt.cli());
debug!("Rem-tags: {:?}", rem);
debug!("Altering things");
alter(&rt, id.clone(), add, rem);
alter(&rt, id.clone(), add, None);
debug!("Altered");
let test_entry = rt.store().get(id).unwrap().unwrap();
@ -306,48 +297,12 @@ mod tests {
assert_eq!(*test_tags, tags_toml_value(vec!["foo"]));
}
#[test]
fn test_tag_add_more_than_remove_adds_tags() {
setup_logging();
debug!("Generating runtime");
let name = "test-tag-add-more-than-remove-adds-tags";
let rt = generate_test_runtime(vec![name,
"--add", "foo",
"--add", "bar",
"--add", "baz",
"--add", "bub",
"--remove", "foo",
"--remove", "bar",
"--remove", "baz",
]).unwrap();
debug!("Creating default entry");
create_test_default_entry(&rt, name).unwrap();
let id = PathBuf::from(String::from(name));
// Manually add tags
let add = get_add_tags(rt.cli());
debug!("Getting 'remove' tags");
let rem = get_remove_tags(rt.cli());
debug!("Rem-tags: {:?}", rem);
debug!("Altering things");
alter(&rt, id.clone(), add, rem);
debug!("Altered");
let test_entry = rt.store().get(id).unwrap().unwrap();
let test_tags = get_entry_tags(&test_entry).unwrap().unwrap();
assert_eq!(*test_tags, tags_toml_value(vec!["bub"]));
}
#[test]
fn test_tag_remove_removes_tag() {
setup_logging();
debug!("Generating runtime");
let name = "test-tag-remove-removes-tag";
let rt = generate_test_runtime(vec![name, "--remove", "foo"]).unwrap();
let rt = generate_test_runtime(vec![name, "remove", "foo"]).unwrap();
debug!("Creating default entry");
create_test_default_entry(&rt, name).unwrap();
@ -375,7 +330,7 @@ mod tests {
setup_logging();
debug!("Generating runtime");
let name = "test-tag-remove-removes-only-to-remove-tag-doesnt-crash-on-nonexistent-tag";
let rt = generate_test_runtime(vec![name, "--remove", "foo"]).unwrap();
let rt = generate_test_runtime(vec![name, "remove", "foo"]).unwrap();
debug!("Creating default entry");
create_test_default_entry(&rt, name).unwrap();
@ -403,7 +358,7 @@ mod tests {
setup_logging();
debug!("Generating runtime");
let name = "test-tag-remove-removes-but-doesnt-crash-on-nonexistent-tag";
let rt = generate_test_runtime(vec![name, "--remove", "foo", "--remove", "bar"]).unwrap();
let rt = generate_test_runtime(vec![name, "remove", "foo", "bar"]).unwrap();
debug!("Creating default entry");
create_test_default_entry(&rt, name).unwrap();

View file

@ -30,23 +30,31 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
.value_name("ID")
.help("Entry to use"))
.subcommand(SubCommand::with_name("add")
.about("Add tags")
.version("0.1")
.arg(Arg::with_name("add-tags")
.short("a")
.long("add")
.index(1)
.takes_value(true)
.value_name("tags")
.required(true)
.multiple(true)
.value_name("tags")
.validator(is_tag)
.help("Add these tags"))
)
.subcommand(SubCommand::with_name("remove")
.about("Remove tags")
.version("0.1")
.arg(Arg::with_name("remove-tags")
.short("r")
.long("remove")
.index(1)
.takes_value(true)
.required(true)
.multiple(true)
.validator(is_tag)
.value_name("tags")
.validator(is_tag)
.help("Remove these tags"))
)
.subcommand(SubCommand::with_name("list")
.about("List tags (default)")

View file

@ -56,6 +56,7 @@ This section contains the changelog from the last release to the next release.
"debug" mode.
* `imag-diary` supports "daily" diaries now.
* `imag-contact` joins multiple emails with "," now
* `imag-tag` commandline was rewritten for positional arguments.
* Bugfixes
* imag does not panic anymore when piping and breaking that pipe, for
example like with `imag store ids | head -n 1`.