xbp 10.30.1

XBP is a zero-config build pack that can also interact with proxies, kafka, sockets, synthetic monitors.
Documentation
use serde_json::json;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;

const PRIMARY_WORKTREE_LINK_PATHS: &[&str] = &["apps/web/.dev.vars", "apps/web/wrangler.dev.jsonc"];

pub fn print_worktree_paths(invocation_dir: &Path) -> Result<(), String> {
    let repo_root = get_repo_root(invocation_dir)?;
    let primary_root = get_primary_worktree_root(invocation_dir)?;
    let is_worktree = !path_eq(&repo_root, &primary_root);
    let shared_state = primary_root.join(".wrangler").join("state");

    println!(
        "{}",
        serde_json::to_string_pretty(&json!({
            "repo_root": repo_root,
            "primary_worktree_root": primary_root,
            "is_worktree_checkout": is_worktree,
            "shared_wrangler_state_path": shared_state,
        }))
        .map_err(|error| format!("Failed to encode JSON output: {}", error))?
    );
    Ok(())
}

pub fn link_dev_vars_from_primary_worktree(invocation_dir: &Path) -> Result<(), String> {
    let repo_root = get_repo_root(invocation_dir)?;
    let primary_root = get_primary_worktree_root(invocation_dir)?;

    if path_eq(&repo_root, &primary_root) {
        println!("Current checkout is the primary worktree; nothing to link.");
        return Ok(());
    }

    let mut linked = Vec::new();
    let mut skipped = Vec::new();
    for rel_path in PRIMARY_WORKTREE_LINK_PATHS {
        match link_from_primary_worktree(rel_path, &primary_root, &repo_root)? {
            LinkOutcome::Linked(path) => linked.push(path),
            LinkOutcome::Unchanged(path) => skipped.push(format!("{path} (already linked)")),
            LinkOutcome::Skipped(path) => skipped.push(path),
        }
    }

    if !linked.is_empty() {
        println!("Linked from primary worktree:");
        for file in linked {
            println!("  - {}", file);
        }
    }

    if !skipped.is_empty() {
        println!("Skipped:");
        for file in skipped {
            println!("  - {}", file);
        }
    }

    Ok(())
}

pub fn get_repo_root(invocation_dir: &Path) -> Result<PathBuf, String> {
    let root = PathBuf::from(run_git(invocation_dir, ["rev-parse", "--show-toplevel"])?);
    Ok(root.canonicalize().unwrap_or(root))
}

pub fn get_primary_worktree_root(invocation_dir: &Path) -> Result<PathBuf, String> {
    let common_dir = get_git_common_dir(invocation_dir)?;
    Ok(common_dir
        .parent()
        .map(Path::to_path_buf)
        .unwrap_or(common_dir))
}

pub fn get_shared_wrangler_state_path(invocation_dir: &Path) -> Result<PathBuf, String> {
    Ok(get_primary_worktree_root(invocation_dir)?
        .join(".wrangler")
        .join("state"))
}

pub fn is_worktree_checkout(invocation_dir: &Path) -> Result<bool, String> {
    let repo_root = get_repo_root(invocation_dir)?;
    let primary_root = get_primary_worktree_root(invocation_dir)?;
    Ok(!path_eq(&repo_root, &primary_root))
}

fn get_git_common_dir(invocation_dir: &Path) -> Result<PathBuf, String> {
    match run_git(
        invocation_dir,
        ["rev-parse", "--path-format=absolute", "--git-common-dir"],
    ) {
        Ok(path) => Ok(PathBuf::from(path)),
        Err(_) => {
            let common_dir_raw = run_git(invocation_dir, ["rev-parse", "--git-common-dir"])?;
            let common_dir = PathBuf::from(&common_dir_raw);
            if common_dir.is_absolute() {
                Ok(common_dir)
            } else {
                Ok(invocation_dir.join(common_dir))
            }
        }
    }
}

fn run_git<const N: usize>(invocation_dir: &Path, args: [&str; N]) -> Result<String, String> {
    let output = Command::new("git")
        .args(args)
        .current_dir(invocation_dir)
        .output()
        .map_err(|error| format!("Failed to run git {}: {}", args.join(" "), error))?;

    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
        let message = if stderr.is_empty() {
            format!(
                "git {} exited with status {}",
                args.join(" "),
                output.status
            )
        } else {
            stderr
        };
        return Err(message);
    }

    let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
    if stdout.is_empty() {
        return Err(format!("git {} returned an empty response", args.join(" ")));
    }
    Ok(stdout)
}

enum LinkOutcome {
    Linked(String),
    Unchanged(String),
    Skipped(String),
}

fn link_from_primary_worktree(
    rel_path: &str,
    primary_root: &Path,
    repo_root: &Path,
) -> Result<LinkOutcome, String> {
    let source = primary_root.join(rel_path);
    let target = repo_root.join(rel_path);
    let Some(target_dir) = target.parent() else {
        return Err(format!(
            "Could not resolve parent directory for {}",
            target.display()
        ));
    };

    if !source.exists() {
        return Ok(LinkOutcome::Skipped(format!(
            "{} (missing in primary worktree)",
            rel_path
        )));
    }

    fs::create_dir_all(target_dir)
        .map_err(|error| format!("Failed to create {}: {}", target_dir.display(), error))?;

    if let Ok(metadata) = fs::symlink_metadata(&target) {
        if metadata.file_type().is_symlink() {
            let current_target = fs::read_link(&target)
                .map_err(|error| format!("Failed to inspect {}: {}", target.display(), error))?;
            let resolved_target = if current_target.is_absolute() {
                current_target
            } else {
                target_dir.join(current_target)
            };
            if path_eq(&resolved_target, &source) {
                return Ok(LinkOutcome::Unchanged(rel_path.to_string()));
            }
            fs::remove_file(&target)
                .map_err(|error| format!("Failed to replace {}: {}", target.display(), error))?;
        } else {
            return Ok(LinkOutcome::Skipped(format!(
                "{} (real file exists)",
                rel_path
            )));
        }
    }

    create_file_symlink(&source, &target)?;
    Ok(LinkOutcome::Linked(rel_path.to_string()))
}

#[cfg(windows)]
fn create_file_symlink(source: &Path, target: &Path) -> Result<(), String> {
    std::os::windows::fs::symlink_file(source, target).map_err(|error| {
        format!(
            "Failed to create symlink {} -> {}: {}",
            target.display(),
            source.display(),
            error
        )
    })
}

#[cfg(not(windows))]
fn create_file_symlink(source: &Path, target: &Path) -> Result<(), String> {
    std::os::unix::fs::symlink(source, target).map_err(|error| {
        format!(
            "Failed to create symlink {} -> {}: {}",
            target.display(),
            source.display(),
            error
        )
    })
}

fn path_eq(left: &Path, right: &Path) -> bool {
    normalize_path(left) == normalize_path(right)
}

fn normalize_path(path: &Path) -> String {
    path.to_string_lossy()
        .replace('\\', "/")
        .to_ascii_lowercase()
}