pray-cli 1.16.0

Package manager for the language placed before inference — Prayfile CLI (binary: pray)
use crate::project_paths::manifest_path;
use pray_core::manifest::parse_manifest;
use pray_core::registry_search::{search_http_registry, search_local_registry, RegistrySearchHit};
use pray_core::{PrayError, PrayResult};
use std::fs;
use std::path::PathBuf;

pub(crate) fn search_command(
    query: String,
    source: Option<String>,
    root: Option<PathBuf>,
    url: Option<String>,
) -> PrayResult<()> {
    let hits = if let Some(root) = root {
        search_local_registry(&root, &query, true)?
    } else if let Some(url) = url {
        search_http_registry(&url, &query, true)?
    } else {
        search_from_prayfile(&query, source.as_deref())?
    };
    print_hits(&hits);
    Ok(())
}

fn search_from_prayfile(
    query: &str,
    source_name: Option<&str>,
) -> PrayResult<Vec<RegistrySearchHit>> {
    let manifest_text = fs::read_to_string(manifest_path()).map_err(|_| {
        PrayError::Unsupported(
            "search requires a Prayfile, or pass --root PATH / --url URL".to_string(),
        )
    })?;
    let manifest = parse_manifest(&manifest_text)?;
    let source = if let Some(name) = source_name {
        manifest
            .sources
            .iter()
            .find(|source| source.name == name)
            .ok_or_else(|| PrayError::Resolution(format!("unknown source: {name}")))?
    } else {
        manifest
            .sources
            .iter()
            .find(|source| {
                source.kind == "registry"
                    || source.kind == "static index"
                    || source.kind == "pray_ssh"
            })
            .or_else(|| manifest.sources.first())
            .ok_or_else(|| {
                PrayError::Resolution(
                    "Prayfile has no sources; pass --root PATH or --url URL".to_string(),
                )
            })?
    };
    if source.kind == "path" {
        let project_root = manifest_path()
            .parent()
            .map(PathBuf::from)
            .unwrap_or_else(|| PathBuf::from("."));
        return search_local_registry(&project_root.join(&source.url), query, true);
    }
    if source.kind == "registry" || source.kind == "static index" {
        return search_http_registry(&source.url, query, true);
    }
    Err(PrayError::Unsupported(format!(
        "search does not support source kind {}",
        source.kind
    )))
}

fn print_hits(hits: &[RegistrySearchHit]) {
    if hits.is_empty() {
        println!("no packages matched");
        return;
    }
    for hit in hits {
        match &hit.summary {
            Some(summary) => println!("{}{summary}", hit.name),
            None => println!("{}", hit.name),
        }
    }
}