Skip to main content
Glama
lib.rs4.46 kB
use std::{ collections::HashMap, io, path::PathBuf, }; use thiserror::Error; #[derive(Debug, Error)] pub enum Buck2ResourcesError { #[error("failed canonicalize path: `{path}`")] Canonicalize { source: io::Error, path: PathBuf }, #[error("looking for key ending with `{ends_with}` returned multiple matches: {matches:?}")] MultipleKeyMatches { ends_with: String, matches: Vec<String>, }, #[error("failed to look up our own executable path")] NoCurrentExe { source: io::Error }, #[error("executable doesn't have a filename: `{executable_path}`")] NoFileName { executable_path: PathBuf }, #[error("failed to find parent directory of executable: `{executable_path}`")] NoParentDir { executable_path: PathBuf }, #[error("no resource named `{name}` found in manifest file: `{manifest_path}`")] NoSuchResource { name: String, manifest_path: PathBuf, }, #[error("failed to parse manifest file: `{manifest_path}`")] ParsingFailed { manifest_path: PathBuf, source: serde_json::Error, }, #[error("failed to read manifest file: `{manifest_path}`")] ReadFailed { manifest_path: PathBuf, source: io::Error, }, } pub struct Buck2Resources { inner: HashMap<String, PathBuf>, parent_dir: PathBuf, manifest_path: PathBuf, } impl Buck2Resources { pub fn read() -> Result<Self, Buck2ResourcesError> { let executable_path = std::env::current_exe() .map_err(|source| Buck2ResourcesError::NoCurrentExe { source })?; let parent_dir = match executable_path.parent() { Some(p) => p, None => return Err(Buck2ResourcesError::NoParentDir { executable_path }), }; let file_name = match executable_path.file_name() { Some(f) => f, None => return Err(Buck2ResourcesError::NoFileName { executable_path }), }; let manifest_path = parent_dir.join(format!("{}.resources.json", file_name.to_string_lossy())); let manifest_string = match std::fs::read_to_string(&manifest_path) { Ok(s) => s, Err(source) => { return Err(Buck2ResourcesError::ReadFailed { manifest_path, source, }); } }; let inner: HashMap<String, PathBuf> = serde_json::from_str(&manifest_string).map_err(|source| { Buck2ResourcesError::ParsingFailed { manifest_path: manifest_path.clone(), source, } })?; Ok(Self { inner, parent_dir: parent_dir.to_path_buf(), manifest_path, }) } pub fn get(&self, name: impl AsRef<str>) -> Result<PathBuf, Buck2ResourcesError> { let rel_path = self.inner .get(name.as_ref()) .ok_or_else(|| Buck2ResourcesError::NoSuchResource { name: name.as_ref().to_string(), manifest_path: self.manifest_path.clone(), })?; let path = self.parent_dir.join(rel_path); let path = path .canonicalize() .map_err(|source| Buck2ResourcesError::Canonicalize { source, path })?; Ok(path) } pub fn get_ends_with(&self, name: impl AsRef<str>) -> Result<PathBuf, Buck2ResourcesError> { let ends_with = format!("/{}", name.as_ref()); let mut candidates: Vec<_> = self .inner .keys() .filter_map(|key| { if key.ends_with(&ends_with) { Some(key.as_str()) } else { None } }) .collect(); if candidates.is_empty() { return Err(Buck2ResourcesError::NoSuchResource { name: format!("*{ends_with}"), manifest_path: self.manifest_path.clone(), }); } if candidates.len() >= 2 { return Err(Buck2ResourcesError::MultipleKeyMatches { ends_with, matches: candidates.into_iter().map(|c| c.to_string()).collect(), }); } match candidates.pop() { Some(key) => self.get(key), None => unreachable!("candidates has len == 1"), } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server