use std::collections::HashMap;
use std::env;
use std::path::PathBuf;
use std::process::ExitCode;
use crate::cmd::RemoteModeCmd;
use crate::cmd::WorkspaceCmd;
use clap::{Arg, Command};
use liboxen::model::LocalRepository;
use liboxen::util;
use tracing::level_filters::LevelFilter;
pub mod cli_error;
pub mod cmd;
pub mod helpers;
const SHORT_ABOUT: &str = "🐂 is the AI and machine learning data management toolchain";
const LONG_ABOUT: &str = "
🐂 is the AI and machine learning data management toolchain
📖 If this is your first time using Oxen, check out the CLI docs at:
https://docs.oxen.ai/getting-started/cli
💬 For more support, or to chat with the Oxen team, join our Discord:
https://discord.gg/s3tBEn7Ptg
";
fn oxen_stack_size() -> usize {
env::var("OXEN_STACK_SIZE")
.ok()
.and_then(|s| s.parse::<usize>().ok())
.unwrap_or(liboxen::constants::OXEN_STACK_SIZE)
}
fn main() -> ExitCode {
let runtime = tokio::runtime::Builder::new_multi_thread()
.thread_stack_size(oxen_stack_size())
.enable_io()
.enable_time()
.build()
.unwrap();
runtime.block_on(async_main())
}
async fn async_main() -> ExitCode {
let _tracing_guard = match util::telemetry::init_tracing("oxen", LevelFilter::OFF) {
Ok(guard) => Some(guard),
Err(e) => {
eprintln!("[ERROR] Failed to initialize tracing for oxen:\n{e}");
None
}
};
let cmds: Vec<Box<dyn cmd::RunCmd>> = vec![
Box::new(cmd::AddCmd),
Box::new(cmd::BranchCmd),
Box::new(cmd::CheckoutCmd),
Box::new(cmd::CleanCmd),
Box::new(cmd::CloneCmd),
Box::new(cmd::CommitCmd),
Box::new(cmd::ConfigCmd),
Box::new(cmd::CreateRemoteCmd),
Box::new(cmd::DbCmd),
Box::new(cmd::DeleteRemoteCmd),
Box::new(cmd::DFCmd),
Box::new(cmd::DiffCmd),
Box::new(cmd::DownloadCmd),
Box::new(cmd::FetchCmd),
Box::new(cmd::EmbeddingsCmd),
Box::new(cmd::InfoCmd),
Box::new(cmd::InitCmd),
Box::new(cmd::LoadCmd),
Box::new(cmd::LogCmd),
Box::new(cmd::LsCmd),
Box::new(cmd::MergeCmd),
Box::new(cmd::MigrateCmd),
Box::new(cmd::MooCmd),
Box::new(cmd::NodeCmd),
Box::new(cmd::PruneCmd),
Box::new(cmd::FsckCmd),
Box::new(cmd::PullCmd),
Box::new(cmd::PushCmd),
Box::new(cmd::RestoreCmd),
Box::new(cmd::RemoteCmd),
Box::new(cmd::RmCmd),
Box::new(cmd::SaveCmd),
Box::new(cmd::SchemasCmd),
Box::new(cmd::StatusCmd),
Box::new(cmd::TreeCmd),
Box::new(cmd::UploadCmd),
Box::new(cmd::WorkspaceCmd),
];
let mut command = Command::new("oxen")
.version(liboxen::constants::OXEN_VERSION)
.about(SHORT_ABOUT)
.long_about(LONG_ABOUT)
.subcommand_required(true)
.arg_required_else_help(true)
.allow_external_subcommands(true)
.arg(
Arg::new("config-dir")
.long("config-dir")
.value_parser(clap::value_parser!(PathBuf))
.global(true)
.help(
"Directory for oxen's user and auth config files \
(overrides $OXEN_CONFIG_DIR; defaults to ~/.config/oxen/)",
),
);
let mut runners: HashMap<String, Box<dyn cmd::RunCmd>> = HashMap::new();
for cmd in cmds {
command = command.subcommand(cmd.args());
runners.insert(cmd.name().to_string(), cmd);
}
let matches = command.get_matches();
if let Some(dir) = matches.get_one::<PathBuf>("config-dir") {
util::fs::set_oxen_config_dir(dir.clone());
}
let is_remote_repo = match LocalRepository::from_current_dir() {
Ok(repo) => repo.is_remote_mode(),
Err(_) => false,
};
match matches.subcommand() {
Some((command, args)) => {
if let Some(runner) = runners.get(command) {
if is_remote_repo {
match command {
"add" | "df" | "diff" | "rm" => {
match WorkspaceCmd::run_subcommands(command, args).await {
Ok(_) => {}
Err(err) => {
cli_error::print_error(&err);
return ExitCode::FAILURE;
}
}
return ExitCode::SUCCESS;
}
"commit" | "checkout" | "pull" | "restore" | "status" => {
match RemoteModeCmd::run_subcommands(command, args).await {
Ok(_) => {}
Err(err) => {
cli_error::print_error(&err);
return ExitCode::FAILURE;
}
}
return ExitCode::SUCCESS;
}
"embeddings" | "merge" | "push" | "workspace" => {
eprintln!(
"Command `oxen {command}` not implemented for remote-mode repositories"
);
return ExitCode::FAILURE;
}
_ => {} }
}
match runner.run(args).await {
Ok(_) => {}
Err(err) => {
cli_error::print_error(&err);
return ExitCode::FAILURE;
}
}
} else {
eprintln!("Unknown command `oxen {command}`");
return ExitCode::FAILURE;
}
}
_ => unreachable!(), }
ExitCode::SUCCESS
}