pijul 1.0.0-alpha

The sound distributed version control system.
use crate::repository::Repository;
use crate::Error;
use libpijul::pristine::MutTxnT;
use libpijul::{MutTxnTExt, TxnTExt};
use std::path::PathBuf;

#[derive(Clap, Debug)]
pub struct Reset {
    #[clap(long = "repository")]
    repo_path: Option<PathBuf>,
    #[clap(long = "channel")]
    channel: Option<String>,
    #[clap(long = "dry-run")]
    dry_run: bool,
    #[clap(long = "change")]
    change: Option<String>,
    files: Vec<PathBuf>,
}

impl Reset {
    pub fn run(self) -> Result<(), anyhow::Error> {
        let has_repo_path = self.repo_path.is_some();
        let mut repo = Repository::find_root(self.repo_path)?;
        let mut txn = repo.pristine.mut_txn_begin();
        use libpijul::pristine::TxnT;
        let channel_name = repo.config.get_current_channel(self.channel.as_ref());
        let mut channel = if let Some(channel) = txn.load_channel(&channel_name) {
            channel
        } else if self.change.is_some() {
            txn.open_or_create_channel(&channel_name)?
        } else {
            return Err((Error::NoSuchChannel {
                channel: channel_name.to_string(),
            })
            .into());
        };
        if self.channel.is_some() {
            repo.config.current_channel = self.channel;
            repo.save_config()?;
        }
        if self.dry_run {
            if self.files.len() > 1 {
                return Err(Error::CannotDryReset.into());
            }
            let (pos, _ambiguous) = if has_repo_path {
                let root = std::fs::canonicalize(repo.path.join(&self.files[0]))?;
                let path = root.strip_prefix(&repo.path)?.to_str().unwrap();
                txn.follow_oldest_path(&repo.changes, &channel, &path)?
            } else {
                let path = self.files[0].to_str().unwrap();
                txn.follow_oldest_path(&repo.changes, &channel, &path)?
            };
            txn.output_file(
                &repo.changes,
                &channel,
                pos,
                &mut libpijul::vertex_buffer::Writer::new(std::io::stdout()),
            )?;
        } else {
            if let Some(ch) = self.change {
                let (hash, _) = txn.hash_from_prefix(&ch)?;
                txn.apply_change_rec(&repo.changes, &mut channel, hash)?
            }
            if self.files.is_empty() {
                txn.output_repository_no_pending(
                    &mut repo.working_copy,
                    &repo.changes,
                    &mut channel,
                    "",
                    true,
                )?;
            } else {
                for root in self.files.iter() {
                    let root = std::fs::canonicalize(&root)?;
                    let path = root.strip_prefix(&repo.path)?.to_str().unwrap();
                    txn.output_repository_no_pending(
                        &mut repo.working_copy,
                        &repo.changes,
                        &mut channel,
                        &path,
                        true,
                    )?;
                }
            }
            txn.commit()?
        }
        Ok(())
    }
}