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}