pijul 0.7.0

A patch-based distributed version control system, easy to use and fast. Command-line interface.
use clap::{SubCommand, Arg, ArgMatches};
use error::{ErrorKind, Error};
use commands::{BasicOptions, StaticSubcommand};
use std::io::{Write,stderr};
use std::process::exit;
use meta;
use meta::KeyType;
use base64::{encode_config, URL_SAFE_NO_PAD};

pub fn invocation() -> StaticSubcommand {
    return SubCommand::with_name("keys")
        .about("Manage signing and SSH keys")
        .arg(Arg::with_name("repository")
             .long("repository")
             .help("The repository where to record, defaults to the current directory.")
             .takes_value(true)
             .required(false))
        .arg(Arg::with_name("generate-signing-key")
             .long("generate-signing")
             .help("Generate a signing key.")
             .takes_value(false)
             .required(false))
        .arg(Arg::with_name("sign")
             .long("sign")
             .help("Challenge to sign.")
             .takes_value(true)
             .required(false))
        .arg(Arg::with_name("generate-SSH-key")
             .long("generate-ssh")
             .help("Generate an SSH key.")
             .takes_value(false)
             .required(false))
        .arg(Arg::with_name("local")
             .long("local")
             .help("Save keys for this repository only")
             .takes_value(false)
             .required(false));
}

pub struct Params<'a> {
    pub generate_signing_key: bool,
    pub generate_ssh_key: bool,
    pub challenge: Option<&'a str>,
    pub local: bool,
}

pub fn parse_args<'a>(args: &'a ArgMatches) -> Params<'a> {
    Params {
        generate_signing_key: args.is_present("generate-signing-key"),
        generate_ssh_key: args.is_present("generate-SSH-key"),
        challenge: args.value_of("sign"),
        local: args.is_present("local"),
    }
}

pub fn run(arg_matches: &ArgMatches) -> Result<(), Error> {
    let opts = BasicOptions::from_args(arg_matches)?;
    let args = parse_args(arg_matches);

    let dot_pijul = if args.local {
        Some(opts.repo_dir())
    } else {
        None
    };

    if args.generate_signing_key {
        if let Some(ref dot_pijul) = dot_pijul {
            meta::generate_key(&dot_pijul, KeyType::Signing)?
        } else {
            meta::generate_global_key(KeyType::Signing)?
        }
    }

    if let Some(ref challenge) = args.challenge {
        match meta::load_global_or_local_key(dot_pijul.as_ref(), KeyType::Signing) {
            Ok(key) => {
                let sig = key.sign(challenge.as_bytes());
                println!("{}", encode_config(&sig, URL_SAFE_NO_PAD))
            }
            Err(e) => {
                panic!("Could not find key: {:?}", e)
            }
        }
    }

    if args.generate_ssh_key {
        if let Some(ref dot_pijul) = dot_pijul {
            meta::generate_key(&dot_pijul, KeyType::SSH)?
        } else {
            meta::generate_global_key(KeyType::SSH)?
        }
    }

    Ok(())
}

pub fn explain(r: Result<(), Error>) {
    if let Err(Error(kind, _)) = r {
        if let ErrorKind::InARepository(p) = kind {
            writeln!(stderr(), "Repository {} already exists", p.display()).unwrap();
        } else {
            writeln!(stderr(), "error: {}", kind).unwrap();
        }
        exit(1)
    }
}