use std::io::Write;
use std::path::PathBuf;
use canonical_path::CanonicalPathBuf;
use clap::Clap;
use libpijul::{MutTxnT, MutTxnTExt, TxnTExt};
use log::{debug, info};
use crate::repository::Repository;
#[derive(Clap, Debug)]
pub struct Mv {
#[clap(long = "repository")]
repo_path: Option<PathBuf>,
paths: Vec<PathBuf>,
}
impl Mv {
pub fn run(mut self) -> Result<(), anyhow::Error> {
let repo = Repository::find_root(self.repo_path.clone())?;
let to = if let Some(to) = self.paths.pop() {
to
} else {
return Ok(());
};
let to = path(&self.repo_path, to);
let is_dir = if let Ok(m) = std::fs::metadata(&to) {
m.is_dir()
} else {
false
};
if !is_dir && self.paths.len() > 1 {
return Ok(());
}
let mut txn = repo.pristine.mut_txn_begin();
let repo_path = CanonicalPathBuf::canonicalize(&repo.path)?;
for p in self.paths {
debug!("p = {:?}", p);
let source = std::fs::canonicalize(&path(&self.repo_path, p.clone()))?;
let target = if is_dir { to.join(p) } else { to.clone() };
debug!("target = {:?}", target);
std::fs::rename(&source, &target)?;
let target = std::fs::canonicalize(&target)?;
let source = source.strip_prefix(&repo_path)?;
let target = target.strip_prefix(&repo_path)?;
debug!("moving {:?} -> {:?}", source, target);
txn.move_file(&source.to_string_lossy(), &target.to_string_lossy())?
}
txn.commit()?;
Ok(())
}
}
fn path(root: &Option<PathBuf>, path: PathBuf) -> PathBuf {
if let Some(ref p) = root {
p.join(path)
} else {
path
}
}
#[derive(Clap, Debug)]
pub struct Ls {
#[clap(long = "repository")]
repo_path: Option<PathBuf>,
}
impl Ls {
pub fn run(self) -> Result<(), anyhow::Error> {
let repo = Repository::find_root(self.repo_path)?;
let txn = repo.pristine.txn_begin()?;
let mut stdout = std::io::stdout();
for p in txn.iter_working_copy() {
let p = p?.1;
writeln!(stdout, "{}", p)?;
}
Ok(())
}
}
#[derive(Clap, Debug)]
pub struct Add {
#[clap(long = "repository")]
repo_path: Option<PathBuf>,
#[clap(short = 'r', long = "recursive")]
recursive: bool,
#[clap(short = 'f', long = "force")]
force: bool,
paths: Vec<PathBuf>,
}
impl Add {
pub fn run(self) -> Result<(), anyhow::Error> {
let repo = Repository::find_root(self.repo_path.clone())?;
let mut txn = repo.pristine.mut_txn_begin();
let threads = num_cpus::get();
let repo_path = CanonicalPathBuf::canonicalize(&repo.path)?;
let mut stderr = std::io::stderr();
for path in self.paths.iter() {
info!("Adding {:?}", path);
let path = CanonicalPathBuf::canonicalize(&path)?;
debug!("{:?}", path);
let meta = std::fs::metadata(&path)?;
debug!("{:?}", meta);
if !self.force
&& !libpijul::working_copy::filesystem::filter_ignore(
repo_path.as_ref(),
path.as_ref(),
meta.is_dir(),
)
{
continue;
}
if self.recursive {
use libpijul::working_copy::filesystem::*;
if let Ok((full, prefix)) = get_prefix(Some(repo_path.as_ref()), path.as_path()) {
repo.working_copy.add_prefix_rec(
&mut txn,
repo_path.clone(),
full.clone(),
&prefix,
threads,
)?
}
} else {
let path = if let Ok(path) = path.as_path().strip_prefix(&repo_path.as_path()) {
path
} else {
continue;
};
let path_str = path.to_str().unwrap();
if !txn.is_tracked(&path_str)? {
if let Err(e) = txn.add(&path_str, meta.is_dir()) {
writeln!(stderr, "{}", e)?;
}
}
}
}
txn.commit()?;
Ok(())
}
}
#[derive(Clap, Debug)]
pub struct Remove {
#[clap(long = "repository")]
repo_path: Option<PathBuf>,
paths: Vec<PathBuf>,
}
impl Remove {
pub fn run(self) -> Result<(), anyhow::Error> {
let repo = Repository::find_root(self.repo_path.clone())?;
let mut txn = repo.pristine.mut_txn_begin();
let repo_path = CanonicalPathBuf::canonicalize(&repo.path)?;
for path in self.paths.iter() {
debug!("{:?}", path);
if let Some(p) = path.file_name() {
if let Some(p) = p.to_str() {
if p.ends_with('~') || (p.starts_with('#') && p.ends_with('#')) {
continue;
}
}
}
let path = path.canonicalize()?;
let path = if let Ok(path) = path.strip_prefix(&repo_path.as_path()) {
path
} else {
continue;
};
let path_str = path.to_str().unwrap();
if txn.is_tracked(&path_str)? {
txn.remove_file(&path_str)?;
}
}
txn.commit()?;
Ok(())
}
}