use clap;
use clap::ArgMatches;
pub type StaticSubcommand = clap::App<'static, 'static>;
mod ask;
mod fs_operation;
pub mod remote;
mod ssh_auth_attempts;
pub mod add;
pub mod apply;
pub mod branches;
pub mod checkout;
pub mod clone;
pub mod credit;
pub mod dependencies;
pub mod diff;
pub mod dist;
pub mod fork;
pub mod generate_completions;
pub mod grep;
pub mod hooks;
pub mod info;
pub mod init;
pub mod key;
pub mod log;
pub mod ls;
pub mod mv;
pub mod patch;
pub mod prune;
pub mod pull;
pub mod push;
pub mod record;
pub mod remote_command;
pub mod remove;
pub mod revert;
pub mod rollback;
pub mod sign;
pub mod status;
pub mod tag;
pub mod unrecord;
mod fold_until;
use error::Error;
use libpijul::fs_representation::{RepoPath, RepoRoot};
use libpijul::Hash;
use libpijul::{fs_representation, Inode, Repository, Txn, DEFAULT_BRANCH};
use rand;
use std::borrow::Cow;
use std::env::current_dir;
use std::env::var;
use std::fs::{canonicalize, create_dir, metadata};
use std::io::{stderr, Write};
use std::path::{Path, PathBuf};
use std::process::exit;
pub fn all_command_invocations() -> Vec<StaticSubcommand> {
return vec![
log::invocation(),
info::invocation(),
init::invocation(),
record::invocation(),
unrecord::invocation(),
add::invocation(),
pull::invocation(),
push::invocation(),
apply::invocation(),
clone::invocation(),
remove::invocation(),
mv::invocation(),
ls::invocation(),
revert::invocation(),
patch::invocation(),
fork::invocation(),
branches::invocation(),
prune::invocation(),
checkout::invocation(),
diff::invocation(),
credit::invocation(),
dist::invocation(),
key::invocation(),
rollback::invocation(),
status::invocation(),
dependencies::invocation(),
tag::invocation(),
sign::invocation(),
generate_completions::invocation(),
grep::invocation(),
remote_command::invocation(),
];
}
pub fn get_wd(repository_path: Option<&Path>) -> Result<PathBuf, Error> {
debug!("get_wd: {:?}", repository_path);
match repository_path {
None => Ok(canonicalize(current_dir()?)?),
Some(a) if a.is_relative() => Ok(canonicalize(current_dir()?.join(a))?),
Some(a) => Ok(canonicalize(a)?),
}
}
pub fn assert_no_containing_repo(dir: &Path) -> Result<(), Error> {
if metadata(dir).is_ok() {
if fs_representation::find_repo_root(&canonicalize(dir)?).is_some() {
return Err(Error::InARepository {
path: dir.to_owned(),
});
}
}
Ok(())
}
pub fn create_repo(dir: &Path) -> Result<(), Error> {
if metadata(dir).is_err() {
create_dir(dir)?;
}
let dir = canonicalize(dir)?;
if fs_representation::find_repo_root(&dir).is_some() {
return Err(Error::InARepository {
path: dir.to_owned(),
});
}
let repo_root = fs_representation::create(&dir, rand::thread_rng())?;
let repo = repo_root.open_repo(None)?;
repo.mut_txn_begin(rand::thread_rng())?.commit()?;
Ok(())
}
fn default_explain<R>(command_result: Result<R, Error>) {
debug!("default_explain");
match command_result {
Ok(_) => (),
Err(e) => {
writeln!(stderr(), "error: {}", e).unwrap();
exit(1)
}
}
}
fn validate_base58(x: String) -> ::std::result::Result<(), String> {
if Hash::from_base58(&x).is_some() {
Ok(())
} else {
Err(format!("\"{}\" is invalid base58", x))
}
}
pub struct BasicOptions<'a> {
pub cwd: PathBuf,
pub repo_root: RepoRoot<PathBuf>,
args: &'a ArgMatches<'a>,
}
pub enum ScanScope {
FromRoot,
WithPrefix(RepoPath<PathBuf>, String),
}
impl<'a> BasicOptions<'a> {
pub fn from_args(args: &'a ArgMatches<'a>) -> Result<BasicOptions<'a>, Error> {
let wd = get_wd(args.value_of("repository").map(Path::new))?;
let repo_root = if let Some(r) = fs_representation::find_repo_root(&canonicalize(&wd)?) {
r
} else {
return Err(Error::NotInARepository);
};
Ok(BasicOptions {
cwd: wd,
repo_root: repo_root,
args: args,
})
}
pub fn branch(&self) -> String {
if let Some(b) = self.args.value_of("branch") {
b.to_string()
} else if let Ok(b) = self.repo_root.get_current_branch() {
b
} else {
DEFAULT_BRANCH.to_string()
}
}
pub fn repo_root(&self) -> PathBuf {
self.repo_root.repo_root.clone()
}
pub fn open_repo(&self) -> Result<Repository, Error> {
self.repo_root.open_repo(None).map_err(|e| e.into())
}
pub fn open_and_grow_repo(&self, increase: u64) -> Result<Repository, Error> {
self.repo_root
.open_repo(Some(increase))
.map_err(|e| e.into())
}
pub fn pristine_dir(&self) -> PathBuf {
self.repo_root.pristine_dir()
}
pub fn patches_dir(&self) -> PathBuf {
self.repo_root.patches_dir()
}
pub fn scan_scope(&self) -> Result<ScanScope, Error> {
if let Some(prefix) = self.args.value_of("dir") {
let root = self
.args
.value_of("repository")
.map(|root| Path::new(root).to_path_buf())
.unwrap_or(current_dir()?);
Ok(ScanScope::WithPrefix(
relative_repo_path(&self.repo_root, &root, prefix)?,
prefix.into(),
))
} else {
Ok(ScanScope::FromRoot)
}
}
fn dir_inode(&self, txn: &Txn) -> Result<Inode, Error> {
use libpijul::ROOT_INODE;
if let Some(dir) = self.args.value_of("dir") {
let dir = if Path::new(dir).is_relative() {
let root = if let Some(root) = self.args.value_of("repository") {
Path::new(root).to_path_buf()
} else {
current_dir()?
};
root.join(&dir).canonicalize()?
} else {
Path::new(dir).canonicalize()?
};
let dir = self.repo_root.relativize(&dir)?;
debug!("{:?}", dir);
let inode = txn.find_inode(&dir)?;
debug!("{:?}", inode);
Ok(inode)
} else {
Ok(ROOT_INODE)
}
}
}
fn remote_pijul_cmd() -> Cow<'static, str> {
if let Ok(cmd) = var("REMOTE_PIJUL") {
Cow::Owned(cmd)
} else {
Cow::Borrowed("pijul")
}
}
pub fn relative_repo_path(
repo_root: &RepoRoot<PathBuf>,
base: &PathBuf,
dir: &str,
) -> Result<RepoPath<PathBuf>, Error> {
let dir = if Path::new(dir).is_relative() {
base.join(&dir).canonicalize()?
} else {
Path::new(dir).canonicalize()?
};
Ok(repo_root.relativize(&dir)?.to_owned())
}
pub fn pretty_repo_path(
repo_root: &RepoRoot<impl AsRef<Path>>,
path: &RepoPath<impl AsRef<Path>>,
cwd: &Path,
) -> PathBuf {
let abs_path = repo_root.absolutize(path);
pathdiff::diff_paths(&abs_path, cwd).unwrap_or(abs_path)
}