130 lines
3.4 KiB
Rust
Raw Normal View History

use std::path::{Path, PathBuf};
#[derive(Debug, PartialEq)]
pub enum ProjectType {
Maven,
Npm,
Cargo
}
impl ProjectType {
fn detect<P: AsRef<Path>>(path: P) -> Option<ProjectType> {
let project_path: PathBuf = path.as_ref().into();
if project_path.join("pom.xml").is_file() {
return Some(ProjectType::Maven);
} else if project_path.join("package.json").is_file() {
return Some(ProjectType::Npm);
} else if project_path.join("Cargo.toml").is_file() {
return Some(ProjectType::Cargo);
}
None
}
}
#[derive(Debug)]
pub struct Project {
pub project_type: ProjectType,
path: PathBuf
}
impl Project {
2019-02-18 03:05:29 -06:00
pub fn path(&self) -> &Path {
&self.path
}
pub fn info(&self) -> ProjectInfo {
2019-02-18 22:12:49 -06:00
match self.project_type {
ProjectType::Maven => ProjectInfo {
name: "placeholder".into(),
version: "placeholder".into()
},
ProjectType::Npm => ProjectInfo {
name: "placeholder".into(),
version: "placeholder".into()
},
2019-02-18 22:12:49 -06:00
ProjectType::Cargo => self.read_cargo_metadata().into()
}
}
2019-02-18 22:12:49 -06:00
fn read_cargo_metadata(&self) -> cargo_metadata::Metadata {
cargo_metadata::MetadataCommand::new().exec().expect("metadata call failed")
}
}
#[derive(Debug)]
pub struct ProjectInfo {
2019-02-18 22:12:49 -06:00
pub name: String,
pub version: String
}
2019-02-18 22:12:49 -06:00
impl From<cargo_metadata::Metadata> for ProjectInfo {
fn from(metadata: cargo_metadata::Metadata) -> Self {
let root_package_id = metadata.resolve
.expect("non-existent resolve field")
.root
.expect("non-existent root package id");
let package = metadata.packages.into_iter()
.find(|package| package.id == root_package_id)
.expect("failed to find package in metadata");
ProjectInfo {
name: package.name.into(),
version: format!("{}", package.version)
}
}
}
pub struct Scouter {
search_path: PathBuf
}
impl Scouter {
pub fn new<P: AsRef<Path>>(path: P) -> Scouter {
let mut search_path: PathBuf = path.as_ref().into();
if !search_path.is_dir() {
search_path.pop();
}
Scouter {
search_path: search_path
}
}
}
impl Iterator for Scouter {
type Item = Project;
fn next(&mut self) -> Option<Self::Item> {
loop {
let project_type = ProjectType::detect(&self.search_path);
if project_type.is_some()
{
return project_type.map(|project_type| Project {
project_type: project_type,
path: self.search_path.to_owned()
});
}
if !self.search_path.pop()
{
return None;
}
}
}
}
#[cfg(test)]
mod test {
use super::{ProjectType, Scouter};
#[test]
fn test_scouter() {
let mut scouter = Scouter::new(file!());
2019-02-18 22:12:49 -06:00
let project = scouter.next().unwrap();
let project_info = project.info();
assert_eq!(ProjectType::Cargo, project.project_type);
assert_eq!(env!("CARGO_PKG_NAME"), project_info.name);
assert_eq!(env!("CARGO_PKG_VERSION"), project_info.version);
}
}