use super::ensure::execute_ensure_workspace;
use super::exec::{execute_claim, execute_create};
use super::goal::compose_prepared;
use super::{BallSpec, Deps, Payload, Prepared, StartError, StartInputs, Step, lineage};
use crate::binding::work_worktree_path;
use crate::projects::join::JoinState;
use crate::world::{layout_under, seed, tools};
use std::path::{Path, PathBuf};
pub fn resolve_worktree(
payload: &Payload,
repo: Option<&Path>,
balls_state_root: &Path,
name: &str,
claimed: Option<PathBuf>,
) -> Option<PathBuf> {
let (
Payload::Ball {
ball: BallSpec::Existing { id, .. },
..
},
Some(repo),
) = (payload, repo)
else {
return None;
};
Some(claimed.unwrap_or_else(|| existing_worktree(balls_state_root, repo, id, name)))
}
fn existing_worktree(balls_state_root: &Path, project: &Path, id: &str, name: &str) -> PathBuf {
let canonical = work_worktree_path(balls_state_root, project, id, None);
let suffixed = work_worktree_path(balls_state_root, project, id, Some(name));
if !canonical.exists() && suffixed.exists() {
suffixed
} else {
canonical
}
}
pub fn prepare(deps: &Deps, inputs: &StartInputs, ts: &str) -> Result<Prepared, StartError> {
let name = crate::naming::leaf(&inputs.workspace);
let lineage = lineage::select(&inputs.workspace, &inputs.payload);
let config = lineage
.as_deref()
.unwrap_or(crate::control::author::DEFAULT_CONFIG);
let origin = inputs.payload.origin();
let mut claimed: Option<PathBuf> = None;
for step in super::plan(inputs) {
match step {
Step::EnsureSeeded => {
let layout = layout_under(&inputs.yog_data_root);
tools::ensure_shim(&layout.tools, tools::BL, &deps.bl)?;
seed::ensure_seeded(&deps.litany, &deps.state_root, ts, &layout, origin)?;
tools::ensure_control(&layout.tools)?;
}
Step::EnsureWorkspace { workspace } => {
let layout = layout_under(&inputs.yog_data_root);
execute_ensure_workspace(deps, ts, &workspace, config, &layout, origin)?;
}
Step::Create {
project,
title,
body,
} => {
let id = execute_create(
&deps.bl,
&deps.state_root,
ts,
&project,
&title,
&body,
&name,
)?;
return prepare(deps, &with_minted(inputs, id, title, body), ts);
}
Step::Claim { project, id, name } => {
claimed = Some(
execute_claim(
&deps.bl,
&deps.state_root,
ts,
&project,
&id,
&name,
&inputs.balls_state_root,
)?
.worktree,
);
}
Step::Prompt { .. } => {}
}
}
let worktree = resolve_worktree(
&inputs.payload,
inputs.repo.as_deref(),
&inputs.balls_state_root,
&name,
claimed,
);
Ok(Prepared {
lineage,
..compose_prepared(inputs, worktree.as_deref())
})
}
fn with_minted(inputs: &StartInputs, id: String, title: String, body: String) -> StartInputs {
StartInputs {
payload: Payload::Ball {
project: inputs.payload.project().unwrap_or_default(),
ball: BallSpec::Existing {
id,
title,
body,
join: JoinState::ReadyStartable,
tags: Vec::new(),
},
},
..inputs.clone()
}
}