pijul 1.0.0-alpha

The sound distributed version control system.
use crate::repository::*;
use libpijul::pristine::MutTxnT;
use libpijul::MutTxnTExt;
use std::path::PathBuf;
use tempfile::TempDir;

#[derive(Clap, Debug)]
pub struct Clone {
    #[clap(long = "lazy", about = "only download changes with alive contents")]
    lazy: bool,
    #[clap(long = "channel", about = "set the remote channel", default_value = crate::DEFAULT_CHANNEL)]
    channel: String,
    #[clap(
        long = "change",
        about = "clone this change and its dependencies",
        conflicts_with = "state"
    )]
    change: Option<String>,
    #[clap(long = "state", about = "clone this state", conflicts_with = "change")]
    state: Option<String>,
    #[clap(long = "path", about = "clone this path", multiple(true))]
    partial_paths: Vec<String>,
    #[clap(short = 'k', about="Do not check certificates")]
    no_cert_check: bool,
    remote: String,
    path: Option<PathBuf>,
}

impl Clone {
    pub async fn run(self) -> Result<(), anyhow::Error> {
        let mut remote = crate::remote::unknown_remote(&self.remote, &self.channel, self.no_cert_check).await?;

        let path = if let Some(path) = self.path {
            if path.is_relative() {
                let mut p = std::env::current_dir()?;
                p.push(path);
                p
            } else {
                path
            }
        } else {
            std::env::current_dir()?
        };
        debug!("path = {:?}", path);
        let parent = std::fs::canonicalize(path.parent().unwrap())?;
        let temp = TempDir::new_in(&parent)?;
        debug!("temp = {:?}", temp.path());
        let mut repo = Repository::init(Some(temp.path().to_path_buf()))?;
        let mut txn = repo.pristine.mut_txn_begin();
        let mut channel = txn.open_or_create_channel(&self.channel)?;
        if let Some(ref change) = self.change {
            let h = change.parse()?;
            remote
                .clone_tag(&mut repo, &mut txn, &mut channel, &[h])
                .await?
        } else if let Some(ref state) = self.state {
            let h = state.parse()?;
            remote
                .clone_state(&mut repo, &mut txn, &mut channel, h, self.lazy)
                .await?
        } else {
            remote
                .clone_channel(
                    &mut repo,
                    &mut txn,
                    &mut channel,
                    self.lazy,
                    &self.partial_paths,
                )
                .await?;
        }
        txn.output_repository_no_pending(
            &mut repo.working_copy,
            &repo.changes,
            &mut channel,
            "",
            true,
        )?;
        txn.commit()?;
        repo.config.current_channel = Some(self.channel);
        repo.save_config()?;
        std::fs::rename(&temp.into_path(), &path)?;
        Ok(())
    }
}