mod checks;
mod config;
mod glue;
mod init;
mod reconcile;
mod repo;
mod run;
mod sync;
use std::path::PathBuf;
use std::process::ExitCode;
use anyhow::Result;
use clap::{Args, Parser, Subcommand};
use crate::config::Config;
use crate::repo::Repo;
use crate::sync::{Options, Session};
#[derive(Parser)]
#[command(name = "jj-fork", version, about)]
struct Cli {
#[arg(long, global = true)]
config: Option<PathBuf>,
#[command(subcommand)]
command: Command,
}
#[derive(Subcommand)]
enum Command {
Init {
#[arg(long)]
upstream: Option<String>,
},
Check(SyncArgs),
Sync(SyncArgs),
Assemble {
#[command(flatten)]
args: SyncArgs,
#[arg(long)]
candidate: Option<String>,
},
Alias,
}
#[derive(Args)]
struct SyncArgs {
#[arg(long)]
target: Option<String>,
#[arg(long)]
no_fetch: bool,
#[arg(long)]
no_checks: bool,
#[arg(long)]
push: bool,
}
pub fn progress(message: &str) {
eprintln!("jj-fork: {message}");
}
pub fn report(line: &str) {
println!("{line}");
}
fn main() -> ExitCode {
let cli = Cli::parse();
match execute(cli) {
Ok(code) => ExitCode::from(code as u8),
Err(err) => {
eprintln!("jj-fork: error: {err:#}");
ExitCode::from(1)
}
}
}
fn execute(cli: Cli) -> Result<i32> {
let cwd = std::env::var_os("JJ_WORKSPACE_ROOT")
.map(PathBuf::from)
.unwrap_or(std::env::current_dir()?);
if let Command::Alias = cli.command {
init::install_alias(&cwd)?;
return Ok(0);
}
let repo = Repo::discover(&cwd)?;
if let Command::Init {
upstream: Some(url),
} = &cli.command
&& cli.config.is_none()
&& !repo.root.join(config::FILE_NAME).exists()
{
init::write_starter_config(&repo.root, url)?;
}
let config = Config::load(&repo.root, cli.config.as_deref())?;
let options = |args: SyncArgs, candidate: Option<String>| Options {
target: args.target,
candidate,
fetch: !args.no_fetch,
checks: !args.no_checks,
push: args.push,
};
let (mut session, command) = match cli.command {
Command::Init { .. } => {
init::init(&repo, &config)?;
return Ok(0);
}
Command::Alias => unreachable!(),
Command::Check(args) => (Session::new(&repo, &config, options(args, None))?, "check"),
Command::Sync(args) => (Session::new(&repo, &config, options(args, None))?, "sync"),
Command::Assemble { args, candidate } => (
Session::new(&repo, &config, options(args, candidate))?,
"assemble",
),
};
let code = match command {
"check" => session.check()?,
"sync" => session.sync()?,
_ => session.assemble_command()?,
};
session.finish();
Ok(code)
}