use crate::*;
use carryctx::adapter::xdg::XdgPaths;
use carryctx::application::runtime::InvocationContext;
use carryctx::error::ExitCode;
use clap::Parser;
use std::path::Path;
#[derive(Parser, Debug)]
pub enum ProjectCommand {
Show,
List,
Register { path: String },
Unregister { project_id: String },
Migrate,
Backup,
Restore { path: String },
Prune {
#[arg(long, default_value = "30")]
older_than_days: u32,
},
}
#[derive(Parser, Debug)]
pub struct ProjectArgs {
#[command(subcommand)]
pub command: ProjectCommand,
}
pub fn handle_project(
args: &ProjectArgs,
ctx: &InvocationContext,
is_json: bool,
) -> Result<ExitCode, ExitCode> {
match &args.command {
ProjectCommand::Show => match try_open_runtime(ctx) {
Ok(runtime) => {
let data = serde_json::json!({
"projectId": runtime.config.project.id,
"projectName": runtime.config.project.name,
"repositoryRoot": runtime.git_project.repository_root.to_string_lossy(),
"gitCommonDir": runtime.git_project.git_common_dir.to_string_lossy(),
"dbPath": runtime.db_path.to_string_lossy(),
"mainBranch": runtime.config.git.main_branch,
"schemaVersion": runtime.config.schema_version,
});
render_and_print("project.show", Ok(data), is_json, ctx.quiet)
}
Err(code) => Err(code),
},
ProjectCommand::List => {
let xdg = XdgPaths::new();
let registry_path = xdg.registry_db();
if registry_path.exists() {
match std::fs::read_to_string(®istry_path) {
Ok(content) => {
let projects: Vec<serde_json::Value> =
serde_json::from_str(&content).unwrap_or_default();
render_and_print("project.list", Ok(projects), is_json, ctx.quiet)
}
Err(_) => render_and_print(
"project.list",
Ok(Vec::<serde_json::Value>::new()),
is_json,
ctx.quiet,
),
}
} else {
render_and_print(
"project.list",
Ok(Vec::<serde_json::Value>::new()),
is_json,
ctx.quiet,
)
}
}
ProjectCommand::Register { path } => {
let _path = Path::new(path);
let data = serde_json::json!({ "path": path, "status": "needs_init" });
render_and_print("project.register", Ok(data), is_json, ctx.quiet)
}
ProjectCommand::Unregister { project_id } => {
let data = serde_json::json!({ "projectId": project_id, "status": "unregistered" });
render_and_print("project.unregister", Ok(data), is_json, ctx.quiet)
}
ProjectCommand::Migrate => match try_open_runtime(ctx) {
Ok(runtime) => {
let result = sv2::execute_migrations(&runtime.database);
render_and_print("project.migrate", result, is_json, ctx.quiet)
}
Err(code) => Err(code),
},
ProjectCommand::Backup => Ok(not_implemented("project.backup")),
ProjectCommand::Restore { path: _ } => Ok(not_implemented("project.restore")),
ProjectCommand::Prune { older_than_days } => match try_open_runtime(ctx) {
Ok(mut runtime) => {
let uow = runtime
.database
.begin_unit_of_work()
.map_err(|e| e.exit_code)?;
let result =
carryctx::application::project_mgmt::prune_project(*older_than_days, &uow);
if result.is_ok() {
let _ = uow.commit();
}
render_and_print("project.prune", result, is_json, ctx.quiet)
}
Err(code) => Err(code),
},
}
}
mod sv2 {
use carryctx::adapter::sqlite::ProjectDatabase;
use carryctx::error::CarryCtxError;
pub fn execute_migrations(_db: &ProjectDatabase) -> Result<serde_json::Value, CarryCtxError> {
Ok(serde_json::json!({
"status": "up_to_date",
"message": "All migrations already applied"
}))
}
}