use std::io::Write;
use std::path::PathBuf;
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();
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.clone())?;
let txn = repo.pristine.txn_begin()?;
let mut stdout = std::io::stdout();
for (_, p) in txn.iter_working_copy() {
writeln!(stdout, "{}", p)?;
}
Ok(())
}
}
#[derive(Clap, Debug)]
pub struct Add {
#[clap(long = "repository")]
repo_path: Option<PathBuf>,
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 mut stderr = std::io::stderr();
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 meta = std::fs::metadata(&path)?;
let path = if let Ok(path) = path.strip_prefix(&repo.path) {
path
} else {
continue;
};
let path_str = path.to_str().unwrap();
if !txn.is_tracked(&path_str) {
writeln!(stderr, "Adding {:?}", path)?;
info!("Adding {:?}", path);
txn.add(&path_str, meta.is_dir())?
}
}
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();
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) {
path
} else {
continue;
};
let path_str = path.to_str().unwrap();
if txn.is_tracked(&path_str) {
txn.remove_file(&path_str)?;
}
}
txn.commit()?;
Ok(())
}
}