pray-cli 1.16.0

Package manager for the language placed before inference — Prayfile CLI (binary: pray)
use crate::invocation;
use pray_core::lockfile::Lockfile;
use pray_core::manifest::{parse_manifest, read_manifest_text};
use pray_core::resolve::{
    annotate_failed_git_refresh, resolution_may_benefit_from_git_source_refresh, ResolvedProject,
};
use pray_core::resolve_context::ResolveOptions;
use pray_core::{PrayError, PrayResult};
use std::path::{Path, PathBuf};

pub(crate) fn manifest_path() -> PathBuf {
    invocation::manifest_path()
}

pub(crate) fn lockfile_path() -> PathBuf {
    invocation::lockfile_path()
}

pub(crate) fn workspace_root() -> PathBuf {
    invocation::project_root()
}

pub(crate) fn resolve_project_with_options(
    _manifest_path: &Path,
    options: &ResolveOptions,
) -> PrayResult<ResolvedProject> {
    invocation::resolve_current_project(options)
}

pub(crate) fn resolve_project(_manifest_path: &Path) -> PrayResult<ResolvedProject> {
    invocation::resolve_current_project(&ResolveOptions::default())
}

pub(crate) fn resolve_project_with_git_refresh_fallback(
    _manifest_path: &Path,
    options: &ResolveOptions,
    allow_git_refresh_fallback: bool,
) -> PrayResult<ResolvedProject> {
    match invocation::resolve_current_project(options) {
        Ok(project) => Ok(project),
        Err(PrayError::Resolution(message))
            if allow_git_refresh_fallback
                && !options.offline
                && !options.refresh_source_revisions
                && resolution_may_benefit_from_git_source_refresh(&message) =>
        {
            let refreshed_options = ResolveOptions {
                refresh_source_revisions: true,
                ..options.clone()
            };
            match invocation::resolve_current_project(&refreshed_options) {
                Ok(project) => Ok(project),
                Err(error) => Err(annotate_failed_git_refresh(&lockfile_path(), error)),
            }
        }
        Err(error) => Err(error),
    }
}

pub(crate) fn load_manifest() -> PrayResult<pray_core::manifest::Manifest> {
    let text = read_manifest_text(&manifest_path())?;
    let manifest = parse_manifest(&text)?;
    for warning in manifest.deprecation_warnings() {
        eprintln!("{warning}");
    }
    Ok(manifest)
}

pub(crate) fn default_output_for_target(target: &str) -> String {
    match target {
        "tool_a" => "INSTRUCTIONS".to_string(),
        "tool_b" => "TOOL_B".to_string(),
        other => other.to_uppercase(),
    }
}

pub(crate) fn locked_package<'a>(
    lockfile: &'a Lockfile,
    package: &pray_core::resolve::ResolvedPackage,
) -> Option<&'a pray_core::lockfile::LockedPackage> {
    lockfile.package.iter().find(|record| {
        record.name == package.declaration.name
            && record.source.as_deref() == package.declaration.source.as_deref()
    })
}

pub(crate) fn run_project_command<T>(
    arguments: &[String],
    execute: impl FnOnce() -> PrayResult<T>,
) -> PrayResult<T> {
    let transactional = arguments.first().is_some_and(|command| {
        matches!(
            command.as_str(),
            "install"
                | "apply"
                | "update"
                | "unlock"
                | "add"
                | "remove"
                | "render"
                | "plan"
                | "verify"
                | "drift"
        )
    });
    if transactional {
        pray_core::transaction::run(&invocation::project_root(), execute)
    } else {
        execute()
    }
}