mod commands;
mod config;
mod remote;
mod repository;
use std::ffi::OsString;
use std::io::Write;
use std::path::PathBuf;
use anyhow::bail;
use clap::{AppSettings, Clap};
use human_panic::setup_panic;
use crate::commands::*;
const DEFAULT_CHANNEL: &str = "main";
const PROTOCOL_VERSION: usize = 3;
#[derive(Clap, Debug)]
#[clap(
version,
author,
global_setting(AppSettings::ColoredHelp),
setting(AppSettings::InferSubcommands)
)]
pub struct Opts {
#[clap(subcommand)]
pub subcmd: SubCommand,
}
#[derive(Clap, Debug)]
pub enum SubCommand {
Init(Init),
Clone(Clone),
Record(Record),
Diff(Diff),
Log(Log),
Push(Push),
Pull(Pull),
Change(Change),
Channel(Channel),
#[clap(setting = AppSettings::Hidden)]
Protocol(Protocol),
#[cfg(feature = "git")]
Git(Git),
Mv(Mv),
Ls(Ls),
Add(Add),
Remove(Remove),
Reset(Reset),
#[cfg(debug_assertions)]
Debug(Debug),
Fork(Fork),
Unrecord(Unrecord),
Apply(Apply),
Remote(Remote),
Archive(Archive),
Credit(Credit),
#[clap(external_subcommand)]
ExternalSubcommand(Vec<OsString>),
}
#[tokio::main]
async fn main() {
setup_panic!();
env_logger::init();
let opts = Opts::parse();
if let Err(e) = run(opts).await {
writeln!(std::io::stderr(), "Error: {}", e).unwrap_or(());
std::process::exit(1);
} else {
std::process::exit(0);
}
}
#[cfg(unix)]
fn run_external_command(mut command: Vec<OsString>) -> Result<(), std::io::Error> {
let args = command.split_off(1);
let mut cmd: OsString = "pijul-".into();
cmd.push(&command[0]);
use std::os::unix::process::CommandExt;
let err = std::process::Command::new(&cmd).args(args).exec();
report_external_command_error(&command[0], err);
}
#[cfg(windows)]
fn run_external_command(mut command: Vec<OsString>) -> Result<(), std::io::Error> {
let args = command.split_off(1);
let mut cmd: OsString = "pijul-".into();
cmd.push(&command[0]);
let mut spawned = match std::process::Command::new(&cmd).args(args).spawn() {
Ok(spawned) => spawned,
Err(e) => {
report_external_command_error(&command[0], e);
}
};
let status = spawned.wait()?;
std::process::exit(status.code().unwrap_or(1))
}
fn report_external_command_error(cmd: &OsString, err: std::io::Error) -> ! {
if err.kind() == std::io::ErrorKind::NotFound {
writeln!(std::io::stderr(), "No such subcommand: {:?}", cmd).unwrap_or(());
} else {
writeln!(std::io::stderr(), "Error while running {:?}: {}", cmd, err).unwrap_or(());
}
std::process::exit(1)
}
async fn run(opts: Opts) -> Result<(), anyhow::Error> {
match opts.subcmd {
SubCommand::Log(l) => l.run(),
SubCommand::Init(init) => init.run(),
SubCommand::Clone(clone) => clone.run().await,
SubCommand::Record(record) => record.run().await,
SubCommand::Diff(diff) => diff.run(),
SubCommand::Push(push) => push.run().await,
SubCommand::Pull(pull) => pull.run().await,
SubCommand::Change(change) => change.run(),
SubCommand::Channel(channel) => channel.run(),
SubCommand::Protocol(protocol) => protocol.run(),
#[cfg(feature = "git")]
SubCommand::Git(git) => git.run(),
SubCommand::Mv(mv) => mv.run(),
SubCommand::Ls(ls) => ls.run(),
SubCommand::Add(add) => add.run(),
SubCommand::Remove(remove) => remove.run(),
SubCommand::Reset(reset) => reset.run(),
#[cfg(debug_assertions)]
SubCommand::Debug(debug) => debug.run(),
SubCommand::Fork(fork) => fork.run(),
SubCommand::Unrecord(unrecord) => unrecord.run(),
SubCommand::Apply(apply) => apply.run(),
SubCommand::Remote(remote) => remote.run(),
SubCommand::Archive(archive) => archive.run().await,
SubCommand::Credit(credit) => credit.run(),
SubCommand::ExternalSubcommand(command) => Ok(run_external_command(command)?),
}
}
pub fn current_dir() -> Result<PathBuf, anyhow::Error> {
if let Ok(cur) = std::env::current_dir() {
Ok(cur)
} else {
bail!("Cannot access working directory")
}
}