use std::io::Write;
use std::path::PathBuf;
use clap::Clap;
use libpijul::{Hash, Merkle, MutTxnTExt, TxnT, TxnTExt};
use log::debug;
use crate::repository::Repository;
#[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')]
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(mut 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 mut p) = self.prefix {
if !p.is_empty() && !p.ends_with("/") {
p.push('/');
}
}
if let Some(ref rem) = self.remote {
debug!("unknown");
let mut remote = crate::remote::unknown_remote(
None,
rem,
if let Some(ref channel) = self.channel {
channel
} else {
crate::DEFAULT_CHANNEL
},
self.no_cert_check,
)
.await?;
if let crate::remote::RemoteRepo::LocalChannel(_) = remote {
if let Some(ref mut path) = self.repo_path {
path.clear();
path.push(rem);
}
} else {
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 f = std::fs::File::create(&p)?;
remote
.archive(self.prefix, state.map(|x| (x, &extra[..])), f)
.await?;
return Ok(());
}
}
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 = libpijul::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() {
writeln!(
std::io::stderr(),
"There were {} conflicts",
conflicts.len()
)?
}
}
Ok(())
}
}