pijul 1.0.0-alpha

The sound distributed version control system.
use crate::repository::Repository;
use libanu::pristine::{Hash, Merkle, TxnT};
use libanu::{MutTxnTExt, TxnTExt};
use std::path::PathBuf;

#[derive(Clap, Debug)]
pub struct Archive {
    #[clap(long = "repository")]
    repo_path: Option<PathBuf>,
    #[clap(long = "channel")]
    channel: Option<String>,
    #[clap(long = "remote")]
    remote: Option<String>,
    #[clap(short = 'k', about="Do not check certificates")]
    no_cert_check: bool,
    #[clap(long = "state")]
    state: Option<String>,
    #[clap(long = "change", multiple = true)]
    change: Vec<String>,
    #[clap(long = "prefix")]
    prefix: Option<String>,
    #[clap(short = 'o')]
    name: String,
}

impl Archive {
    pub async fn run(self) -> Result<(), anyhow::Error> {
        let state: Option<Merkle> = if let Some(ref state) = self.state {
            Some(state.parse()?)
        } else {
            None
        };
        let mut extra: Vec<Hash> = Vec::new();
        for h in self.change.iter() {
            extra.push(h.parse()?);
        }

        if let Some(ref rem) = self.remote {
            debug!("unknown");
            let mut remote = crate::remote::unknown_remote(
                rem,
                if let Some(ref channel) = self.channel {
                    channel
                } else {
                    crate::DEFAULT_CHANNEL
                },
                self.no_cert_check
            )
            .await?;
            let mut p = std::path::Path::new(&self.name).to_path_buf();
            if !self.name.ends_with(".tar.gz") {
                p.set_extension("tar.gz");
            }
            let mut f = std::fs::File::create(&p)?;
            remote
                .archive(self.prefix, state.map(|x| (x, &extra[..])), &mut f)
                .await?;
        } else if let Ok(repo) = Repository::find_root(self.repo_path.clone()) {
            let channel_name = repo.config.get_current_channel(self.channel.as_ref());
            let mut p = std::path::Path::new(&self.name).to_path_buf();
            if !self.name.ends_with(".tar.gz") {
                p.set_extension("tar.gz");
            }
            let mut f = std::fs::File::create(&p)?;
            let mut tarball = libanu::output::Tarball::new(&mut f, self.prefix);
            let conflicts = if let Some(state) = state {
                let mut txn = repo.pristine.mut_txn_begin();
                let mut channel = txn.load_channel(&channel_name).unwrap();
                txn.archive_with_state(
                    &repo.changes,
                    &mut channel,
                    state,
                    &extra[..],
                    &mut tarball,
                )?
            } else {
                let txn = repo.pristine.txn_begin()?;
                let channel = txn.load_channel(&channel_name).unwrap();
                txn.archive(&repo.changes, &channel, &mut tarball)?
            };
            if !conflicts.is_empty() {
                eprintln!("There were {} conflicts", conflicts.len())
            }
        }
        Ok(())
    }
}