use std::collections::HashMap;
use std::path::PathBuf;
use crate::repository::*;
use anyhow::bail;
use clap::Clap;
use libpijul::{MutTxnT, MutTxnTExt};
use log::debug;
#[derive(Clap, Debug)]
pub struct Clone {
#[clap(long = "lazy")]
lazy: bool,
#[clap(long = "channel", default_value = crate::DEFAULT_CHANNEL)]
channel: String,
#[clap(long = "change", conflicts_with = "state")]
change: Option<String>,
#[clap(long = "state", conflicts_with = "change")]
state: Option<String>,
#[clap(long = "path", multiple(true))]
partial_paths: Vec<String>,
#[clap(short = 'k')]
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(None, &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 if let Some(path) = remote.repo_name() {
let mut p = std::env::current_dir()?;
p.push(path);
p
} else {
bail!("Could not infer repository name from {:?}", self.remote)
};
debug!("path = {:?}", path);
let path_ = path.clone();
ctrlc::set_handler(move || {
std::fs::remove_dir_all(&path_).unwrap_or(());
std::process::exit(130)
})
.unwrap_or(());
let repo_path = RepoPath(path);
let mut repo = Repository::init(Some(repo_path.0.clone()))?;
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?;
}
let progress = indicatif::ProgressBar::new_spinner();
progress.set_style(
indicatif::ProgressStyle::default_spinner().template("{spinner} Outputting repository"),
);
progress.enable_steady_tick(100);
txn.output_repository_no_pending(
&mut repo.working_copy,
&repo.changes,
&mut channel,
&mut HashMap::new(),
"",
true,
None,
)?;
remote.finish().await?;
txn.commit()?;
progress.set_style(
indicatif::ProgressStyle::default_spinner().template("✓ Outputting repository"),
);
progress.finish();
repo.config.current_channel = Some(self.channel);
if let crate::remote::RemoteRepo::Local(ref l) = remote {
repo.config.default_remote = std::fs::canonicalize(&l.root)?
.to_str()
.map(|x| x.to_string());
} else {
repo.config.default_remote = Some(self.remote);
}
repo.save_config()?;
std::mem::drop(repo);
std::mem::forget(repo_path);
Ok(())
}
}
struct RepoPath(PathBuf);
impl Drop for RepoPath {
fn drop(&mut self) {
std::fs::remove_dir_all(&self.0).unwrap_or(());
}
}