use std::path::{Path, PathBuf};
use std::{fmt, fs};
use cairo_lang_project::PROJECT_FILE_NAME;
use crate::toolchain::scarb::SCARB_TOML;
#[cfg(test)]
#[path = "project_manifest_path_test.rs"]
mod project_manifest_path_test;
const MAX_CRATE_DETECTION_DEPTH: usize = 20;
#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
pub enum ProjectManifestPath {
CairoProject(PathBuf),
Scarb(PathBuf),
}
impl ProjectManifestPath {
pub fn discover(path: &Path) -> Option<ProjectManifestPath> {
return find_in_parent_dirs(path.to_path_buf(), PROJECT_FILE_NAME)
.map(ProjectManifestPath::CairoProject)
.or_else(|| {
find_in_parent_dirs(path.to_path_buf(), SCARB_TOML).map(ProjectManifestPath::Scarb)
});
fn find_in_parent_dirs(mut path: PathBuf, target_file_name: &str) -> Option<PathBuf> {
for _ in 0..MAX_CRATE_DETECTION_DEPTH {
if !path.pop() {
return None;
}
let manifest_path = path.join(target_file_name);
if fs::metadata(&manifest_path).is_ok() {
return Some(manifest_path);
};
}
None
}
}
}
impl fmt::Display for ProjectManifestPath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ProjectManifestPath::CairoProject(path) | ProjectManifestPath::Scarb(path) => {
fmt::Display::fmt(&path.display(), f)
}
}
}
}