<commit_before>extern crate clap;
#[macro_use] extern crate log;
extern crate semver;
extern crate toml;
#[macro_use] extern crate version;

extern crate libimagstore;
extern crate libimagrt;
extern crate libimagentrytag;
extern crate libimagutil;

use std::process::exit;

use libimagrt::runtime::Runtime;
use libimagentrytag::tagable::Tagable;
use libimagstore::storeid::build_entry_path;

mod ui;

use ui::build_ui;

use libimagutil::trace::trace_error;

fn main() {
    let name = "imag-store";
    let version = &version!()[..];
    let about = "Direct interface to the store. Use with great care!";
    let ui = build_ui(Runtime::get_default_cli_builder(name, version, about));
    let rt = {
        let rt = Runtime::new(ui);
        if rt.is_ok() {
            rt.unwrap()
        } else {
            println!("Could not set up Runtime");
            println!("{:?}", rt.unwrap_err());
            exit(1);
        }
    };

    let id = rt.cli().value_of("id").unwrap(); // enforced by clap
    rt.cli()
        .subcommand_name()
        .map_or_else(
            || {
                let add = rt.cli().value_of("add");
                let rem = rt.cli().value_of("remove");

                alter(&rt, id, add, rem);
            },
            |name| {
                debug!("Call: {}", name);
                match name {
                    "list" => list(id, &rt),
                    _ => {
                        warn!("Unknown command");
                        // More error handling
                    },
                };
            });
}

fn alter(rt: &Runtime, id: &str, add: Option<&str>, rem: Option<&str>) {
    let path = {
        match build_entry_path(rt.store(), id) {
            Err(e) => {
                trace_error(&e);
                exit(1);
            },
            Ok(s) => s,
        }
    };
    debug!("path = {:?}", path);

    rt.store()
        // "id" must be present, enforced via clap spec
        .retrieve(path)
        .map(|mut e| {
            add.map(|tags| {
                for tag in tags.split(',') {
                    info!("Adding tag '{}'", tag);
                    if let Err(e) = e.add_tag(String::from(tag)) {
                        trace_error(&e);
                    }
                }
            });

            rem.map(|tags| {
                for tag in tags.split(',') {
                    info!("Removing tag '{}'", tag);
                    if let Err(e) = e.remove_tag(String::from(tag)) {
                        trace_error(&e);
                    }
                }
            });
        })
        .map_err(|e| {
            info!("No entry.");
            trace_error(&e);
        })
        .ok();
}

fn list(id: &str, rt: &Runtime) {
    let path = {
        match build_entry_path(rt.store(), id) {
            Err(e) => {
                trace_error(&e);
                exit(1);
            },
            Ok(s) => s,
        }
    };
    debug!("path = {:?}", path);

    let entry = rt.store().retrieve(path.clone());
    if entry.is_err() {
        debug!("Could not retrieve '{:?}' => {:?}", id, path);
        warn!("Could not retrieve entry '{}'", id);
        trace_error(&entry.unwrap_err());
        exit(1);
    }
    let entry = entry.unwrap();

    let scmd = rt.cli().subcommand_matches("list").unwrap(); // safe, we checked in main()<commit_msg>Rewrite adding/removing to allow adding and removing multiple tags<commit_after>extern crate clap;
#[macro_use] extern crate log;
extern crate semver;
extern crate toml;
#[macro_use] extern crate version;

extern crate libimagstore;
extern crate libimagrt;
extern crate libimagentrytag;
extern crate libimagutil;

use std::process::exit;

use libimagrt::runtime::Runtime;
use libimagentrytag::tagable::Tagable;
use libimagstore::storeid::build_entry_path;

mod ui;

use ui::build_ui;

use libimagutil::trace::trace_error;

fn main() {
    let name = "imag-store";
    let version = &version!()[..];
    let about = "Direct interface to the store. Use with great care!";
    let ui = build_ui(Runtime::get_default_cli_builder(name, version, about));
    let rt = {
        let rt = Runtime::new(ui);
        if rt.is_ok() {
            rt.unwrap()
        } else {
            println!("Could not set up Runtime");
            println!("{:?}", rt.unwrap_err());
            exit(1);
        }
    };

    let id = rt.cli().value_of("id").unwrap(); // enforced by clap
    rt.cli()
        .subcommand_name()
        .map_or_else(
            || {
                let add = rt.cli().values_of("add").map(|o| o.map(String::from));
                let rem = rt.cli().values_of("remove").map(|o| o.map(String::from));

                alter(&rt, id, add, rem);
            },
            |name| {
                debug!("Call: {}", name);
                match name {
                    "list" => list(id, &rt),
                    _ => {
                        warn!("Unknown command");
                        // More error handling
                    },
                };
            });
}

fn alter<SI: Iterator<Item = String>>(rt: &Runtime, id: &str, add: Option<SI>, rem: Option<SI>) {
    let path = {
        match build_entry_path(rt.store(), id) {
            Err(e) => {
                trace_error(&e);
                exit(1);
            },
            Ok(s) => s,
        }
    };
    debug!("path = {:?}", path);

    rt.store()
        // "id" must be present, enforced via clap spec
        .retrieve(path)
        .map(|mut e| {
            add.map(|tags| {
                for tag in tags {
                    debug!("Adding tag '{:?}'", tag);
                    if let Err(e) = e.add_tag(tag) {
                        trace_error(&e);
                    }
                }
            }); // it is okay to ignore a None here

            rem.map(|tags| {
                for tag in tags {
                    debug!("Removing tag '{:?}'", tag);
                    if let Err(e) = e.remove_tag(tag) {
                        trace_error(&e);
                    }
                }
            }); // it is okay to ignore a None here
        })
        .map_err(|e| {
            info!("No entry.");
            trace_error(&e);
        })
        .ok();
}

fn list(id: &str, rt: &Runtime) {
    let path = {
        match build_entry_path(rt.store(), id) {
            Err(e) => {
                trace_error(&e);
                exit(1);
            },
            Ok(s) => s,
        }
    };
    debug!("path = {:?}", path);

    let entry = rt.store().retrieve(path.clone());
    if entry.is_err() {
        debug!("Could not retrieve '{:?}' => {:?}", id, path);
        warn!("Could not retrieve entry '{}'", id);
        trace_error(&entry.unwrap_err());
        exit(1);
    }
    let entry = entry.unwrap();

    let scmd = rt.cli().subcommand_matches("list").unwrap(); // safe, we checked in main()
{'fraction_non_alphanumeric': 0.15840579710144928, 'fraction_numerical': 0.0011594202898550724, 'mean_word_length': 1.4958408679927668, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5590030', 'n_tokens_mistral': 2102, 'n_tokens_neox': 2043, 'n_words': 477}