pkg/
recipes.rs

1use std::collections::{BTreeSet, HashMap};
2use std::ffi::OsStr;
3use std::path::{Path, PathBuf};
4use std::sync::LazyLock;
5
6use crate::PackageName;
7
8static RECIPE_PATHS: LazyLock<HashMap<PackageName, PathBuf>> = LazyLock::new(|| {
9    let mut recipe_paths = HashMap::new();
10    for entry_res in ignore::Walk::new("recipes") {
11        let entry = entry_res.unwrap();
12        if entry.file_name() == OsStr::new("recipe.sh")
13            || entry.file_name() == OsStr::new("recipe.toml")
14        {
15            let recipe_file = entry.path();
16            let Some(recipe_dir) = recipe_file.parent() else {
17                continue;
18            };
19            let Some(recipe_name) = recipe_dir
20                .file_name()
21                .and_then(|x| x.to_str()?.try_into().ok())
22            else {
23                continue;
24            };
25            if let Some(other_dir) = recipe_paths.insert(recipe_name, recipe_dir.to_path_buf()) {
26                panic!(
27                    "recipe {:?} has two or more entries {:?}, {:?}",
28                    recipe_dir.file_name(),
29                    other_dir,
30                    recipe_dir
31                );
32            }
33        }
34    }
35    recipe_paths
36});
37
38pub fn find(recipe: &str) -> Option<&'static Path> {
39    RECIPE_PATHS.get(recipe).map(PathBuf::as_path)
40}
41
42pub fn list(prefix: impl AsRef<Path>) -> BTreeSet<PathBuf> {
43    let prefix = prefix.as_ref();
44    RECIPE_PATHS
45        .values()
46        .map(|path| prefix.join(path))
47        .collect()
48}