pijul_org / pijul

feature: Fork from a patch

With this patch, it is now possible to create a new branch which contains the minimal dependencies set for a gien patch. This, combined to tags, allows for having a minimal version of git checkout <hash>.

By lthms on May 1, 2018
This patch is not signed.
9vK8MGS5VCPZmautBDFe1QGwjkmqaxZtG2q9cUcfZBwPBHMPTMXhZvP6qz91DtE8L32P9jQhsKVdW7GuuEQhVM1g
This patch is in the following branches:
latest
master
testing



























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
73
74
75
76
77
78
79
80
81
82
83
84
85


86








87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use clap::{SubCommand, ArgMatches, Arg};
use clap::{SubCommand, ArgMatches, Arg, ArgGroup};
use libpijul::{Hash, apply_resize_no_output};
use libpijul::fs_representation::read_patch;
use std::path::PathBuf;
use commands::checkout::checkout;
use error::{Result, ErrorKind, Error};
        .arg(Arg::with_name("patch")
             .long("patch")
             .help("A patch hash, preferably a tag.")
             .takes_value(true)
        .group(ArgGroup::with_name("source")
               .required(false)
               .args(&["branch", "patch"]))
fn patch_dependencies(hash_str: &str,
                      repo_root: &PathBuf)
                      -> Result<Vec<Hash>> {
    let mut current = vec![Hash::from_base58(hash_str).ok_or::<Error>(ErrorKind::WrongHash.into())?];
            let patch = read_patch(&repo_root, hash.as_ref())?;
pub fn has_branch(opts: &BasicOptions, branch_name: &str) -> Result<bool> {
            debug!("Creating a new branch {:?} with dependencies of {:?}",
                   to,
                   hash);
            apply_resize_no_output(&opts.repo_root, to, deps.iter())?;
            checkout(&opts, to, false)
            let branch = txn.open_branch(&opts.branch())?;
            set_current_branch(&opts.repo_root, to)?;
use clap::{Arg, ArgGroup, ArgMatches, SubCommand};
use commands::checkout::checkout;
use libpijul::fs_representation::RepoRoot;
use libpijul::{apply_resize_no_output, Hash};
use rand;
use std::mem;
use std::path::Path; // PathBuf;

use super::{default_explain, BasicOptions, StaticSubcommand};
use error::Error;

pub fn invocation() -> StaticSubcommand {
    return SubCommand::with_name("fork")
        .about("Create a new branch")
        .arg(
            Arg::with_name("repository")
                .long("repository")
                .help("Local repository.")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("branch")
                .long("branch")
                .help("Branch.")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("patch")
                .long("patch")
                .help("A patch hash, preferably a tag.")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("to")
                .help("Name of the new branch.")
                .takes_value(true)
                .required(true),
        )
        .group(
            ArgGroup::with_name("source")
                .required(false)
                .args(&["branch", "patch"]),
        );
}

fn patch_dependencies(
    hash_str: &str,
    repo_root: &RepoRoot<impl AsRef<Path>>,
) -> Result<Vec<Hash>, Error> {
    let mut deps = Vec::new();
    let mut current = vec![Hash::from_base58(hash_str).ok_or::<Error>(Error::WrongHash)?];
    let mut next = Vec::new();

    while !current.is_empty() {
        for hash in current.drain(..) {
            deps.push(hash.clone());
            let patch = repo_root.read_patch(hash.as_ref())?;

            for hash_dep in patch.dependencies().iter() {
                let h = hash_dep.to_owned();

                if !deps.contains(&h) {
                    next.push(h);
                }
            }
        }

        mem::swap(&mut next, &mut current);
    }

    deps.reverse();

    Ok(deps)
}

pub fn has_branch(opts: &BasicOptions, branch_name: &str) -> Result<bool, Error> {
    let repo = opts.open_repo()?;
    let txn = repo.txn_begin()?;

    Ok(txn.has_branch(branch_name))
}

pub fn run(args: &ArgMatches) -> Result<(), Error> {
    let opts = BasicOptions::from_args(args)?;
    let to = args.value_of("to").unwrap();
    let repo = opts.open_repo()?;
    let mut txn = repo.mut_txn_begin(rand::thread_rng())?;

    if !txn.has_branch(to) {
        let branch = txn.open_branch(&opts.branch())?;
        let new_branch = txn.fork(&branch, to)?;
        try!(txn.commit_branch(branch));
        try!(txn.commit_branch(new_branch));
        try!(txn.commit());
        set_current_branch(&opts.repo_root, to)?;
        Ok(())
    if !has_branch(&opts, to)? {
        if let Some(ref hash) = args.value_of("patch") {
            debug!(
                "Creating a new branch {:?} with dependencies of {:?}",
                to, hash
            );

            let deps = patch_dependencies(hash, &opts.repo_root)?;

            apply_resize_no_output(&opts.repo_root, to, deps.iter(), |_, _| ())?;

            println!("Branch {:?} has been created.", to);

            checkout(&opts, to, false, None)
        } else {
            let repo = opts.open_repo()?;
            let mut txn = repo.mut_txn_begin(rand::thread_rng())?;

            let br = opts.branch();
            let branch = txn.open_branch(&br)?;
            let new_branch = txn.fork(&branch, to)?;

            txn.commit_branch(branch)?;
            txn.commit_branch(new_branch)?;

            let partials = txn
                .iter_partials(&br)
                .take_while(|&(k, _)| k.as_str() == &br)
                .map(|(_, v)| v)
                .collect::<Vec<_>>();
            for &key in partials.iter() {
                txn.put_partials(to, key)?;
            }
            txn.commit()?;

            opts.repo_root.set_current_branch(to)?;

            Ok(())
        }
    } else {