pijul_org / pijul

refactor: Simplify pijul-tag implementation using record functions

By lthms on April 26, 2018
This patch is not signed.
7bt3NxyEBe3CC7vGdHRDV3u4wcaqjXdaAsePiG6zKy8r5FsrCB5tEEcuUn7ZUhjEGkwsQuqLMZCFbZ7EuKq4utJx
This patch is in the following branches:
latest
master
testing
4
5

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

70
71
use clap::{Arg, ArgMatches, SubCommand};
use commands::hooks::run_hook;
use commands::tag::tag_args;
use commands::{ask, BasicOptions, StaticSubcommand};
use error::Error;
use libpijul;
use libpijul::fs_representation::{in_repo_root, RepoPath, RepoRoot};
use libpijul::patch::{PatchFlags, Record};
use libpijul::{Hash, InodeUpdate, Key, MutTxn, Patch, PatchId, RecordState, Repository};
use meta::{load_signing_key, Global, Meta};
use rand;
use std::collections::HashSet;
use std::fs::canonicalize;
use std::fs::{metadata, OpenOptions};
use std::io::Write;
use std::mem::drop;
use std::path::{Path, PathBuf};
use std::str::FromStr;

pub fn record_args(sub: StaticSubcommand) -> StaticSubcommand {
    sub.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("branch")
             .long("branch")
             .help("The branch where to record, defaults to the current branch.")
             .takes_value(true)
             .required(false))
        .arg(Arg::with_name("date")
             .long("date")
             .help("The date to use to record the patch, default is now.")
             .takes_value(true)
             .required(false))
        .arg(Arg::with_name("message")
             .short("m")
             .long("message")
             .help("The name of the patch to record")
             .takes_value(true))
        .arg(Arg::with_name("description")
             .short("d")
             .long("description")
             .help("The description of the patch to record")
             .takes_value(true))
        .arg(Arg::with_name("no-editor")
             .long("no-editor")
             .help("Do not use an editor to write the patch name and description, even if the variable is set in the configuration file")
             .takes_value(false))
        .arg(Arg::with_name("author")
             .short("A")
             .long("author")
             .help("Author of this patch (multiple occurrences allowed)")
             .takes_value(true))
        .arg(Arg::with_name("patience")
             .long("patience")
             .help("Use patience diff instead of the default (Myers diff)")
             .conflicts_with("myers")
             .takes_value(false))
        .arg(Arg::with_name("myers")
             .long("myers")
             .help("Use Myers diff")
             .conflicts_with("patience")
             .takes_value(false))
}

pub fn invocation() -> StaticSubcommand {
    return tag_args(
    return record_args(
        SubCommand::with_name("record")


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18


19
20
21
22

use commands::record::{record_args, decide_authors, decide_patch_message};
    record_args(SubCommand::with_name("rollback")
use clap::{Arg, ArgMatches, SubCommand};

use super::{ask, default_explain, validate_base58, BasicOptions, StaticSubcommand};
use meta::{load_signing_key, Global, Meta};
use std::collections::HashSet;
use std::path::Path;

use chrono;
use libpijul::fs_representation::{patch_file_name, RepoPath, RepoRoot};
use libpijul::patch::{Patch, PatchFlags};
use libpijul::{apply_resize, apply_resize_no_output, Hash, HashRef, PatchId};
use std::collections::HashMap;
use std::fs::File;
use std::io::BufReader;
use std::iter;
use std::mem::drop;
use std::str::FromStr;

use commands::tag::tag_args;
use commands::record::{decide_authors, decide_patch_message};
use commands::record::{decide_authors, decide_patch_message, record_args};
use error::Error;

pub fn invocation() -> StaticSubcommand {
    tag_args(SubCommand::with_name("rollback")














1
2
3

4
5
6
7
8
9
10
11
12
13
14





































15


























16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48



























49
50
51
52
53
54
55
56
57
58
59
60
61



















62


63
64
65
66
67
68
69
70
71
72
use clap::{SubCommand, ArgMatches, Arg};
use clap::{SubCommand, ArgMatches};
use commands::record::{decide_patch_message, decide_authors, record_args};
    record_args(SubCommand::with_name("tag")
        .about("create a patch (a \"tag\") with no changes, and all currently applied patches as dependencies"))
        if global.author.len() == 0 {
            global.author = authors[0].clone();
            save_global = true;
        let (patch_name, description) = decide_patch_message(patch_name_arg,
                                                             patch_descr_arg,
                                                             !args.is_present("no-editor"),
                                                             &opts.repo_root,
                                                             &meta,
                                                             &global)?;
use super::default_explain;
use super::record;
use chrono;
use commands::{BasicOptions, StaticSubcommand, ask};
use clap::{ArgMatches, SubCommand};
use commands::hooks::run_hook;
use commands::record::{decide_authors, decide_patch_message, record_args};
use commands::{BasicOptions, StaticSubcommand};
use error::Error;
use libpijul::patch::PatchFlags;
use libpijul::Hash;
use meta::{load_signing_key, Global, Meta};
use std::collections::HashSet;
use std::mem::drop;

pub fn tag_args(sub: StaticSubcommand) -> StaticSubcommand {
    sub.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("branch")
             .long("branch")
             .help("The branch where to record, defaults to the current branch.")
             .takes_value(true)
             .required(false))
        .arg(Arg::with_name("date")
             .long("date")
             .help("The date to use to record the patch, default is now.")
             .takes_value(true)
             .required(false))
        .arg(Arg::with_name("message")
             .short("m")
             .long("message")
             .help("The name of the patch to record")
             .takes_value(true))
        .arg(Arg::with_name("description")
             .short("d")
             .long("description")
             .help("The description of the patch to record")
             .takes_value(true))
        .arg(Arg::with_name("no-editor")
             .long("no-editor")
             .help("Do not use an editor to write the patch name and description, even if the variable is set in the configuration file")
             .takes_value(false))
        .arg(Arg::with_name("author")
             .short("A")
             .long("author")
             .help("Author of this patch (multiple occurrences allowed)")
             .takes_value(true))
}

pub fn invocation() -> StaticSubcommand {
    return SubCommand::with_name("tag")
        .about("create a patch (a \"tag\") with no changes, and all currently applied patches as dependencies")
        .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("branch")
             .long("branch")
             .help("The branch where to record, defaults to the current branch.")
             .takes_value(true)
             .required(false))
        .arg(Arg::with_name("message")
             .short("m")
             .long("message")
             .help("The name of the patch to record")
             .takes_value(true))
        .arg(Arg::with_name("no-editor")
             .long("no-editor")
             .help("Do not use an editor to write the patch name and description, even if the variable is set in the configuration file")
             .takes_value(false))
        .arg(Arg::with_name("author")
             .short("A")
             .long("author")
             .help("Author of this patch (multiple occurrences allowed)")
             .takes_value(true))
    record_args(
        SubCommand::with_name("tag").about(
            "Create a tag, i.e. an empty patch with all patches on the branch as dependencies",
        ),
    )
}

pub fn run(args: &ArgMatches) -> Result<Option<Hash>, Error> {
    let opts = BasicOptions::from_args(args)?;
    let patch_name_arg = args.value_of("message");
    let patch_descr_arg = args.value_of("description");
    let authors_arg = args.values_of("author").map(|x| x.collect::<Vec<_>>());
    let branch_name = opts.branch();

    let mut save_meta = false;

    let (mut global, save_global) = Global::load().map(|g| (g, false)).unwrap_or_else(|e| {
        info!("loading global key, error {:?}", e);
        (Global::new(), true)
    });

    let mut meta = match Meta::load(&opts.repo_root) {
        Ok(m) => m,
        Err(_) => {
            save_meta = true;
            Meta::new()
        }
    };

    let repo = opts.open_repo()?;
    let patch = {
        let txn = repo.txn_begin()?;
        debug!("meta:{:?}", meta);
        let authors: Vec<String> = if let Some(ref authors) = authors_arg {
            let authors: Vec<String> = authors.iter().map(|x| x.to_string()).collect();
            {
                if meta.authors.len() == 0 {
                    meta.authors = authors.clone();
                    save_meta = true
                }
                if global.author.len() == 0 {
                    global.author = authors[0].clone();
                    save_global = true
                }
            }
            authors
        } else {
            if meta.authors.len() > 0 {
                meta.authors.clone()
            } else if global.author.len() > 0 {
                vec![global.author.clone()]
            } else {
                let authors = ask::ask_authors()?;
                save_meta = true;
                meta.authors = authors.clone();
                save_global = true;
                global.author = authors[0].clone();
                authors
            }
        };

        let authors = decide_authors(authors_arg, &meta, &global)?;

        if meta.authors.len() == 0 {
            meta.authors = authors.clone();
            save_meta = true;
        }

        if global.author.is_none() {
            global.author = Some(authors[0].clone());
        }

        debug!("authors:{:?}", authors);
        let (patch_name, description) = if let Some(ref m) = patch_name_arg {
            (m.to_string(), None)
        } else {
            // Sometimes, it can be handy to just write the patch name from
            // the CLI. We therefore provide a new flag, `no-editor`, that
            // forces pijul to fallback into the default behaviour even if
            // an editor is configured.
            let maybe_editor = if !args.is_present("no-editor") {
                // There are two places where one can configure an editor to
                // use: globally and locally. If it is configured in both
                // location, we prefer the local setting.
                if meta.editor.is_some() {
                    meta.editor.as_ref()
                } else {
                    global.editor.as_ref()
                }
            } else {
                None
            };

            ask::ask_patch_name(&opts.repo_root, maybe_editor)?
        };
        let (patch_name, description) = decide_patch_message(
            patch_name_arg,
            patch_descr_arg,
            String::from(""),
            !args.is_present("no-editor"),
            &opts.repo_root,
            &meta,
            &global,
        )?;