pijul_org / pijul

fix: Prevent checkout to fail in case Sanakirja requires more space

By lthms on May 1, 2018
This patch is not signed.
84ayE3waYHs6dJkefP7JtFxfhGcCKh5dc9pgSdWfzcypCZ5fYBc3eP37WaGkpMMLX14m1gy16q5vgT1naWP4kNqt
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
        checkout(&opts, branch, args.is_present("force"))
        Err(ErrorKind::NoSuchBranch.into())
pub fn checkout(opts: &BasicOptions, branch: &str, force: bool) -> Result<()> {
        match try_checkout(opts, branch, force, provision) {
            },
            x => {
                return x
pub fn try_checkout(opts: &BasicOptions, branch: &str, force: bool, provision: u64) -> Result<()> {
    let current_branch = get_current_branch(&opts.repo_root)?;
        if txn.iter_inodes(None).any(|(_, ch)| ch.status != FileStatus::Ok) {
            return Err(ErrorKind::PendingChanges.into());
        txn.record(&mut record, &current_branch, &opts.repo_root, None)?;
            return Err(ErrorKind::PendingChanges.into());
    if !txn.get_branch(branch).is_some() {
        return Err(ErrorKind::NoSuchBranch.into());
    }
    txn.output_repository(
        &branch,
        &opts.repo_root,
        None,
        &UnsignedPatch::empty().leave_unsigned(),
        &HashSet::new()
    )?;
    set_current_branch(&opts.repo_root, branch)?;
    println!("Current branch: {:?}", get_current_branch(&opts.repo_root)?);
use clap::{Arg, ArgMatches, SubCommand};

use super::{default_explain, BasicOptions, StaticSubcommand};
use error::Error;
use libpijul::fs_representation::{in_repo_root, RepoPath};
use libpijul::patch::UnsignedPatch;
use libpijul::{FileStatus, RecordState, ToPrefixes};
use rand;
use std::collections::HashSet;
use std::path::Path;

pub fn invocation() -> StaticSubcommand {
    return SubCommand::with_name("checkout")
        .about("Change the current branch")
        .arg(
            Arg::with_name("repository")
                .long("repository")
                .help("Local repository.")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("branch")
                .help("Branch to switch to.")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("path")
                .long("path")
                .help("Partial path to check out.")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("force")
                .short("f")
                .long("force")
                .takes_value(false)
                .help("Only verify that there are no unrecorded files moves, deletions or additions (ignores unrecorded changes in files). Much faster on large repositories."),
        );
}

pub fn run(args: &ArgMatches) -> Result<(), Error> {
    let opts = BasicOptions::from_args(args)?;
    if let Some(branch) = args.value_of("branch") {
        let repo = opts.open_and_grow_repo(409600)?;
        let mut txn = repo.mut_txn_begin(rand::thread_rng())?;
        let current_branch = get_current_branch(&opts.repo_root)?;
        // We need to check at least that there are no file
        // moves/additions/deletions, because these would be
        // overwritten by the checkout, sometimes causing Pijul to
        // panic.
        if args.is_present("force") {
            // Check whether there are file moves.
            if txn.iter_inodes(None).any(|(_, ch)| ch.status != FileStatus::Ok) {
                return Err(ErrorKind::PendingChanges.into());
            }
        } else {
            // Check whether there are more general changes.
            let mut record = RecordState::new();
            txn.record(&mut record, &current_branch, &opts.repo_root, None)?;
            let (changes, _) = record.finish();
        checkout(
            &opts,
            branch,
            args.is_present("force"),
            args.value_of("path").map(|p| RepoPath(Path::new(p))),
        )
    } else {
        Err(Error::NoSuchBranch)
    }
}

            if !changes.is_empty() {
                return Err(ErrorKind::PendingChanges.into());
pub fn checkout(
    opts: &BasicOptions,
    branch: &str,
    force: bool,
    partial_path: Option<RepoPath<&Path>>,
) -> Result<(), Error> {
    let mut force = force;
    let mut provision = 409600;

    loop {
        match try_checkout(opts, branch, force, provision, partial_path) {
            Err(ref e) if e.lacks_space() => {
                provision = provision * 2;
                force = true;
            }
            x => return x,
        }
    }
}

        if !txn.get_branch(branch).is_some() {
            return Err(ErrorKind::NoSuchBranch.into());
pub fn try_checkout(
    opts: &BasicOptions,
    branch_name: &str,
    force: bool,
    provision: u64,
    partial_path: Option<RepoPath<&Path>>,
) -> Result<(), Error> {
    let repo = opts.open_and_grow_repo(provision)?;
    let mut txn = repo.mut_txn_begin(rand::thread_rng())?;
    let current_branch = opts.repo_root.get_current_branch()?;
    // We need to check at least that there are no file
    // moves/additions/deletions, because these would be
    // overwritten by the checkout, sometimes causing Pijul to
    // panic.
    if force {
        // Check whether there are file moves.
        if txn
            .iter_inodes(None)
            .any(|(_, ch)| ch.status != FileStatus::Ok)
        {
            return Err(Error::PendingChanges);
        }
    } else {
        // Check whether there are more general changes.
        let mut record = RecordState::new();
        let current_branch = txn.open_branch(&current_branch)?;
        txn.record(
            libpijul::DiffAlgorithm::default(),
            &mut record,
            &current_branch,
            &opts.repo_root,
            &in_repo_root(),
        )?;
        txn.commit_branch(current_branch)?;
        let (changes, _) = record.finish();

        txn.output_repository(
            &branch,
            &opts.repo_root,
            None,
            &UnsignedPatch::empty().leave_unsigned(),
            &HashSet::new()
        )?;
        )?;
        txn.commit()?;
        if !changes.is_empty() {
            return Err(Error::PendingChanges);
        }
    }

        set_current_branch(&opts.repo_root, branch)?;
    debug!("output repository");

    } else {
        Err(ErrorKind::NoSuchBranch.into())
    }
    let mut branch = if let Some(branch) = txn.get_branch(branch_name) {
        branch
    } else {
        return Err(Error::NoSuchBranch);
    };
    let pref = if let Some(partial) = partial_path {
        (&[partial][..]).to_prefixes(&txn, &branch)
    } else {
        (&[][..] as &[RepoPath<&Path>]).to_prefixes(&txn, &branch)
    };
    txn.output_repository(
        &mut branch,
        &opts.repo_root,
        &pref,
        &UnsignedPatch::empty().leave_unsigned(),
        &HashSet::new(),
    )?;
    txn.commit_branch(branch)?;

    txn.commit()?;

    opts.repo_root.set_current_branch(branch_name)?;

    println!("Current branch: {:?}", opts.repo_root.get_current_branch()?);
    Ok(())
}