use camino::{Utf8Path, Utf8PathBuf};
use serde::Serialize;
use super::{Manager, canonical_dir};
use crate::error::RkError;
pub use crate::self_depend::manager::{MISE_FILES, ManagerFile, first_mention, manager_files};
#[derive(Debug, Clone, Serialize)]
pub struct Already {
pub manager: Manager,
pub file: String,
pub line: usize,
}
#[derive(Debug, Clone)]
pub struct Target {
pub path: Utf8PathBuf,
pub tech: Option<&'static str>,
pub managers: Vec<ManagerFile>,
pub envrc_use_flake: bool,
pub already: Vec<Already>,
}
impl Target {
#[must_use]
pub fn file_of(&self, manager: Manager) -> Option<&ManagerFile> {
self.managers.iter().find(|m| m.manager == manager)
}
#[must_use]
pub const fn default_file(manager: Manager) -> &'static str {
manager.default_file()
}
}
pub fn observe(path: &Utf8Path, dep_name: Option<&str>) -> Result<Target, RkError> {
let path = canonical_dir(path, "target")?;
let managers = manager_files(&path, dep_name)?;
let envrc_use_flake = match std::fs::read_to_string(path.join(".envrc")) {
Ok(text) => text.lines().any(|line| {
let mut words = line.split_whitespace();
words.next() == Some("use") && words.next() == Some("flake")
}),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => false,
Err(e) => return Err(RkError::Io(e)),
};
let already = dep_name
.map(|name| {
managers
.iter()
.filter_map(|m| {
first_mention(&m.text, name).map(|line| Already {
manager: m.manager,
file: m.file.clone(),
line,
})
})
.collect()
})
.unwrap_or_default();
Ok(Target {
tech: tech_or_node(&path),
path,
managers,
envrc_use_flake,
already,
})
}
#[must_use]
pub fn tech_or_node(dir: &Utf8Path) -> Option<&'static str> {
crate::detect::tech_of(dir.as_std_path())
.or_else(|| dir.join("package.json").is_file().then_some("node"))
}
#[cfg(test)]
mod tests {
use super::{Manager, Target, tech_or_node};
#[test]
fn the_default_file_is_the_managers_own() {
for manager in Manager::ALL {
assert_eq!(Target::default_file(manager), manager.default_file());
}
}
#[test]
fn node_is_read_from_package_json_after_the_version_files() {
let dir = tempfile::tempdir().expect("a scratch dir");
let root = camino::Utf8Path::from_path(dir.path()).expect("utf-8");
assert_eq!(tech_or_node(root), None);
std::fs::write(root.join("package.json"), "{}").expect("writes");
assert_eq!(tech_or_node(root), Some("node"));
std::fs::write(root.join("Cargo.toml"), "").expect("writes");
assert_eq!(tech_or_node(root), Some("rust"));
}
}