use std::io::Write;
use std::path::PathBuf;
use anyhow::Result;
use clap::{Args, Subcommand, ValueHint};
use serde::Serialize;
use crate::cli::GlobalArgs;
use crate::constants::SCRATCH_DIR_REL;
use crate::output::NdjsonWriter;
#[derive(Args, Debug)]
pub struct ScratchArgs {
#[command(subcommand)]
pub action: ScratchAction,
}
#[derive(Subcommand, Debug)]
pub enum ScratchAction {
Init(ScratchInitArgs),
}
#[derive(Args, Debug)]
pub struct ScratchInitArgs {
#[arg(
long,
value_hint = ValueHint::DirPath,
help = "Relative staging dir under workspace (default constants::SCRATCH_DIR_REL)"
)]
pub path: Option<PathBuf>,
}
#[derive(Debug, Serialize)]
pub struct ScratchInitEvent {
pub ok: bool,
pub status: &'static str,
pub command: &'static str,
pub action: &'static str,
pub path: String,
pub relative: String,
pub already_existed: bool,
}
#[tracing::instrument(skip_all, fields(command = "scratch"))]
pub fn cmd_scratch(
args: &ScratchArgs,
global: &GlobalArgs,
writer: &mut NdjsonWriter<impl Write>,
) -> Result<()> {
match &args.action {
ScratchAction::Init(init) => cmd_scratch_init(init, global, writer),
}
}
fn cmd_scratch_init(
args: &ScratchInitArgs,
global: &GlobalArgs,
writer: &mut NdjsonWriter<impl Write>,
) -> Result<()> {
let workspace = global.resolve_workspace()?;
let relative = args
.path
.clone()
.unwrap_or_else(|| PathBuf::from(SCRATCH_DIR_REL));
let candidate = if relative.is_absolute() {
relative.clone()
} else {
workspace.join(&relative)
};
let resolved = crate::path_safety::validate_path(&candidate, &workspace)?;
let already = resolved.is_dir();
std::fs::create_dir_all(&resolved)
.map_err(|e| crate::error::AtomwriteError::Io { source: e })?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let _ = std::fs::set_permissions(
&resolved,
std::fs::Permissions::from_mode(crate::constants::DIR_PERMISSIONS),
);
}
let rel_display = relative.to_string_lossy().replace('\\', "/");
writer.write_event(&ScratchInitEvent {
ok: true,
status: "ok",
command: "scratch",
action: "init",
path: resolved.display().to_string(),
relative: rel_display,
already_existed: already,
})?;
Ok(())
}