pray-cli 1.22.0

Package manager for the language placed before inference — Prayfile CLI (binary: pray)
use crate::project_paths::{default_output_for_target, manifest_path};
use crate::registry_ops::write_registry_index;
use pray_core::distribution::{write_registry_distribution_settings, RegistryDistributionSettings};
use pray_core::registry::RegistryIndex;
use pray_core::trust::{write_registry_trust_settings, RegistryTrustSettings};
use pray_core::{PrayError, PrayResult};
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

pub(crate) use crate::commands_init_prayer::prayer_init_command;

pub(crate) fn init_command(targets: Vec<String>) -> PrayResult<()> {
    let manifest_path = manifest_path();
    if manifest_path.exists() {
        return Err(PrayError::Manifest("Prayfile already exists".to_string()));
    }
    let mut text = String::new();
    text.push_str("prayfile \"1\"\n");
    for target in if targets.is_empty() {
        vec!["tool_a".to_string()]
    } else {
        targets
    } {
        text.push_str(&format!(
            "target :{} do\n  output \"{}.md\"\nend\n",
            target,
            default_output_for_target(&target)
        ));
    }
    fs::write(manifest_path, text)?;
    Ok(())
}

pub(crate) fn repo_init_command() -> PrayResult<()> {
    let root = env::current_dir()?;
    let distribution_root = repo_distribution_root(&root);
    let index_path = distribution_root.join("v1/index.json");
    let trust_path = distribution_root.join("v1/trust.json");
    let distribution_path = distribution_root.join("v1/distribution.json");
    if index_path.exists() || trust_path.exists() || distribution_path.exists() {
        return Err(PrayError::Manifest(
            "distribution repo already exists".to_string(),
        ));
    }

    fs::create_dir_all(distribution_root.join("v1/packages"))?;
    fs::create_dir_all(distribution_root.join("v1/artifacts"))?;
    write_registry_index(
        &distribution_root,
        &RegistryIndex {
            spec: "prayfile-distribution-1".to_string(),
            packages: Vec::new(),
        },
    )?;
    write_registry_trust_settings(&distribution_root, &RegistryTrustSettings::default())?;
    write_registry_distribution_settings(
        &distribution_root,
        &RegistryDistributionSettings::default(),
    )?;
    maybe_declare_publish_remote(&root, &distribution_root)?;
    Ok(())
}

fn maybe_declare_publish_remote(project_root: &Path, distribution_root: &Path) -> PrayResult<()> {
    let manifest_path = project_root.join("Prayfile");
    if !manifest_path.exists() {
        return Ok(());
    }
    let text = fs::read_to_string(&manifest_path)?;
    let manifest = pray_core::manifest::parse_manifest(&text)?;
    if !manifest.publish_remotes.is_empty() {
        return Ok(());
    }
    let relative = if distribution_root == project_root {
        ".".to_string()
    } else {
        distribution_root
            .strip_prefix(project_root)
            .map(|path| path.to_string_lossy().replace('\\', "/"))
            .unwrap_or_else(|_| "prayers".to_string())
    };
    let statement = format!("publish \"prayers\", path: \"{relative}\"");
    let mut lines: Vec<String> = text.lines().map(str::to_string).collect();
    let insertion = lines
        .iter()
        .rposition(|line| line.trim_start().starts_with("source "))
        .map(|index| index + 1)
        .or_else(|| {
            lines
                .iter()
                .position(|line| line.trim_start().starts_with("prayfile "))
                .map(|index| index + 1)
        })
        .unwrap_or(1);
    lines.insert(insertion, statement);
    let mut updated = lines.join("\n");
    if !updated.ends_with('\n') {
        updated.push('\n');
    }
    fs::write(manifest_path, updated)?;
    Ok(())
}

fn repo_distribution_root(root: &Path) -> PathBuf {
    if root.file_name().and_then(|value| value.to_str()) == Some("prayers") {
        root.to_path_buf()
    } else {
        root.join("prayers")
    }
}