use std::path::PathBuf;
use clap::Parser;
use crate::{
RUST_CRATES_ROOT, RUST_GIT_ROOT,
assets::extract_buck2_assets,
buck2::Buck2Command,
buckal_error,
bundles::{fetch_buckal_cell, init_buckal_cell, init_modifier},
cache::BuckalCache,
context::BuckalContext,
utils::{UnwrapOrExit, append_buck_out_to_gitignore, ensure_prerequisites, get_buck2_root},
};
#[derive(Parser, Debug)]
pub struct MigrateArgs {
#[clap(long, name = "no-cache")]
pub no_cache: bool,
#[clap(long)]
pub merge: bool,
#[clap(long, value_name = "PATH", default_missing_value = ".", num_args = 0..=1, conflicts_with = "fetch")]
pub init: Option<PathBuf>,
#[clap(long)]
pub fetch: bool,
#[arg(long, conflicts_with = "init")]
pub manifest_path: Option<String>,
}
pub fn execute(args: &MigrateArgs) {
ensure_prerequisites().unwrap_or_exit();
if let Some(init_path) = &args.init {
let cwd = std::env::current_dir().unwrap_or_exit();
let init_root = std::fs::canonicalize(init_path).unwrap_or_exit_ctx(format!(
"failed to resolve init path `{}`",
init_path.display()
));
let existing_root = get_buck2_root().ok();
let root_for_checks = existing_root
.as_ref()
.map(|root| root.as_std_path())
.unwrap_or_else(|| init_root.as_path());
let toolchains_dir = root_for_checks.join("toolchains");
let platforms_dir = root_for_checks.join("platforms");
if toolchains_dir.is_dir() || platforms_dir.is_dir() {
buckal_error!(
"`toolchains/` or `platforms/` directory already exists under `{}`. Please delete them first.",
root_for_checks.display()
);
std::process::exit(1);
}
std::env::set_current_dir(&init_root).unwrap_or_exit_ctx(format!(
"failed to change directory to `{}`",
init_root.display()
));
Buck2Command::init().execute().unwrap_or_exit();
std::env::set_current_dir(&cwd).unwrap_or_exit_ctx(format!(
"failed to change directory back to `{}`",
cwd.display()
));
let buck2_root = existing_root.unwrap_or_else(|| {
get_buck2_root().unwrap_or_exit_ctx("failed to get Buck2 project root")
});
let crates_dir = buck2_root.join(RUST_CRATES_ROOT);
std::fs::create_dir_all(&crates_dir)
.unwrap_or_exit_ctx(format!("failed to create directory at `{}`", crates_dir));
let git_dir = buck2_root.join(RUST_GIT_ROOT);
std::fs::create_dir_all(&git_dir)
.unwrap_or_exit_ctx(format!("failed to create directory at `{}`", git_dir));
append_buck_out_to_gitignore(buck2_root.as_std_path())
.unwrap_or_exit_ctx("failed to update `.gitignore`");
init_buckal_cell(buck2_root.as_std_path()).unwrap_or_exit();
extract_buck2_assets(buck2_root.as_std_path())
.unwrap_or_exit_ctx("failed to extract buck2 assets");
init_modifier(buck2_root.as_std_path()).unwrap_or_exit();
}
if args.fetch {
let cwd = std::env::current_dir().unwrap_or_exit();
fetch_buckal_cell(&cwd).unwrap_or_exit();
}
let mut ctx = BuckalContext::new(args.manifest_path.clone());
ctx.no_merge = !args.merge;
let last_cache = if args.no_cache || BuckalCache::load().is_err() {
BuckalCache::new_empty()
} else {
BuckalCache::load().unwrap_or_exit_ctx("failed to load existing cache")
};
let new_cache = BuckalCache::new(&ctx.nodes_map, &ctx.workspace_root);
let changes = new_cache.diff(&last_cache, &ctx.workspace_root);
changes.apply(&ctx);
new_cache.save();
}