resolve properties for versions of dependencies
This commit is contained in:
parent
3b170f7866
commit
04b94f35b2
8 changed files with 160 additions and 61 deletions
|
|
@ -1,7 +1,7 @@
|
|||
use std::path::Path;
|
||||
use undeepend::maven::project_parser::parse_project;
|
||||
use undeepend::maven::project::parse_project;
|
||||
|
||||
fn main() {
|
||||
let project = parse_project(Path::new("tests/maven/resources/sample_project")).unwrap();
|
||||
println!("{:?}", project);
|
||||
println!("{:?}", project.get_dependencies(&project.root));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@ pub mod metadata;
|
|||
pub mod pom;
|
||||
pub mod pom_view;
|
||||
pub mod pom_parser;
|
||||
pub mod project_parser;
|
||||
pub mod project;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// The Maven variant to parse poms
|
||||
/// These structs is directly modelled after the XML because that is what strong-xml plugin requires
|
||||
|
|
@ -14,7 +15,13 @@ pub struct Pom {
|
|||
pub dependencies: Vec<Dependency>,
|
||||
pub dependency_management: Vec<Dependency>,
|
||||
pub properties: HashMap<String, String>,
|
||||
pub modules: Vec<String>,
|
||||
pub module_names: Vec<String>,
|
||||
pub modules: Vec<Pom>,
|
||||
pub directory: PathBuf,
|
||||
}
|
||||
|
||||
impl Pom {
|
||||
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
|
|
@ -43,12 +50,3 @@ pub struct Dependency {
|
|||
pub artifact_id: String,
|
||||
pub version: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use crate::maven::pom::Pom;
|
||||
|
||||
#[test]
|
||||
fn parse_should_not_fail() {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use crate::maven::pom::{Dependency, Developer, Parent, Pom};
|
|||
use crate::xml::SaxError;
|
||||
use crate::xml::dom_parser::{Node, get_document};
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn get_pom(xml: impl Into<String>) -> Result<Pom, SaxError> {
|
||||
let mut group_id = None;
|
||||
|
|
@ -14,7 +15,7 @@ pub fn get_pom(xml: impl Into<String>) -> Result<Pom, SaxError> {
|
|||
let mut dependencies = vec![];
|
||||
let mut dependency_management = vec![];
|
||||
let mut properties = HashMap::new(); // useless assignment...
|
||||
let mut modules = vec![]; // not useless assignment...
|
||||
let mut module_names = vec![]; // not useless assignment...
|
||||
|
||||
for child in get_document(xml.into().as_str())?.root.children {
|
||||
match child.name.as_str() {
|
||||
|
|
@ -28,7 +29,7 @@ pub fn get_pom(xml: impl Into<String>) -> Result<Pom, SaxError> {
|
|||
"dependencies" => dependencies = get_dependencies(child),
|
||||
"dependencyManagement" => dependency_management = get_dependency_mgmt(child),
|
||||
"properties" => properties = get_properties(child),
|
||||
"modules" => add_modules(child, &mut modules),
|
||||
"modules" => add_modules(child, &mut module_names),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -43,7 +44,9 @@ pub fn get_pom(xml: impl Into<String>) -> Result<Pom, SaxError> {
|
|||
dependencies,
|
||||
dependency_management,
|
||||
properties,
|
||||
modules,
|
||||
module_names,
|
||||
modules: vec![],
|
||||
directory: PathBuf::new(), // resolved later, make optional?
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
139
src/maven/project.rs
Normal file
139
src/maven/project.rs
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
use crate::maven::pom::{Dependency, Pom};
|
||||
use crate::maven::pom_parser::get_pom;
|
||||
use regex::Regex;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
static PROPERTY_EXPR: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"\$\{(.+)}").unwrap());
|
||||
|
||||
pub fn parse_project(project_dir: &Path) -> Result<Project, String> {
|
||||
if !project_dir.is_dir() {
|
||||
return Err(format!("{:?} is not a directory", project_dir));
|
||||
}
|
||||
|
||||
let mut pom_file = project_dir.to_path_buf();
|
||||
pom_file.push(Path::new("pom.xml"));
|
||||
|
||||
let pom_file = fs::read_to_string(pom_file).map_err(|e| e.to_string())?;
|
||||
let mut root = get_pom(pom_file).map_err(|e| e.to_string())?;
|
||||
|
||||
resolve_modules(project_dir, &mut root);
|
||||
Ok(Project { root })
|
||||
}
|
||||
|
||||
fn resolve_modules(project_dir: &Path, pom: &mut Pom) {
|
||||
let mut modules = pom
|
||||
.module_names
|
||||
.iter()
|
||||
.map(|module| read_module_pom(project_dir, module))
|
||||
.collect();
|
||||
for module in &mut modules {
|
||||
resolve_modules(project_dir, module);
|
||||
}
|
||||
pom.modules.append(&mut modules);
|
||||
}
|
||||
|
||||
fn read_module_pom(project_dir: &Path, module: &String) -> Pom {
|
||||
let mut module_dir = project_dir.to_path_buf();
|
||||
module_dir.push(Path::new(module));
|
||||
let mut module_file = module_dir.clone();
|
||||
module_file.push(Path::new("pom.xml"));
|
||||
let module_pom =
|
||||
fs::read_to_string(module_file).expect(format!("Cannot read file {}", module).as_str());
|
||||
|
||||
let mut pom =
|
||||
get_pom(module_pom).expect(format!("Cannot create module pom {}", module).as_str());
|
||||
pom.directory = module_dir;
|
||||
pom
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Project {
|
||||
pub root: Pom,
|
||||
}
|
||||
|
||||
impl Project {
|
||||
pub fn get_dependencies(&self, pom: &Pom) -> Vec<Dependency> {
|
||||
pom.dependencies
|
||||
.iter()
|
||||
.map(|dependency| {
|
||||
let version = self.get_version(pom, &dependency.group_id, &dependency.artifact_id);
|
||||
Dependency {
|
||||
group_id: dependency.group_id.clone(),
|
||||
artifact_id: dependency.artifact_id.clone(),
|
||||
version,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_version(&self, pom: &Pom, group_id: &str, artifact_id: &str) -> Option<String> {
|
||||
pom.dependencies
|
||||
.iter()
|
||||
.find(|d| d.group_id == group_id && d.artifact_id == artifact_id)
|
||||
.and_then(|d| d.version.clone())
|
||||
.and_then(|version| {
|
||||
if PROPERTY_EXPR.is_match(&version) {
|
||||
let property_name = &PROPERTY_EXPR.captures(&version).unwrap()[1];
|
||||
self.get_property(pom, property_name)
|
||||
} else {
|
||||
Some(version)
|
||||
}
|
||||
})
|
||||
.or_else(|| {
|
||||
pom.dependency_management
|
||||
.iter()
|
||||
.find(|d| d.group_id == group_id && d.artifact_id == artifact_id)
|
||||
.and_then(|d| d.version.clone())
|
||||
.and_then(|version| {
|
||||
if PROPERTY_EXPR.is_match(&version) {
|
||||
let property_name = &PROPERTY_EXPR.captures(&version).unwrap()[1];
|
||||
self.get_property(pom, property_name)
|
||||
} else {
|
||||
Some(version)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn get_property(&self, pom: &Pom, name: &str) -> Option<String> {
|
||||
if pom.properties.contains_key(name) {
|
||||
pom.properties.get(name).cloned()
|
||||
} else if let Some(parent) = &pom.parent {
|
||||
if let Some(parent_pom) = self.get_pom(&parent.group_id, &parent.artifact_id) {
|
||||
self.get_property(parent_pom, name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn get_pom<'a>(&'a self, group_id: &str, artifact_id: &str) -> Option<&'a Pom> {
|
||||
fn get_project_pom<'a>(pom: &'a Pom, group_id: &str, artifact_id: &str) -> Option<&'a Pom> {
|
||||
if is_same(pom, group_id, artifact_id) {
|
||||
return Some(pom);
|
||||
} else {
|
||||
for module in &pom.modules {
|
||||
return get_project_pom(module, group_id, artifact_id);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
get_project_pom(&self.root, group_id, artifact_id)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_same(pom: &Pom, group_id: &str, artifact_id: &str) -> bool {
|
||||
if pom.artifact_id == artifact_id {
|
||||
if let Some(pom_group_id) = &pom.group_id {
|
||||
pom_group_id == group_id
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
use crate::maven::pom::Pom;
|
||||
use crate::maven::pom_parser::get_pom;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
pub fn parse_project(project_dir: &Path) -> Result<Project, String> {
|
||||
if !project_dir.is_dir() {
|
||||
return Err(format!("{:?} is not a directory", project_dir));
|
||||
}
|
||||
|
||||
let mut pom_file = project_dir.to_path_buf();
|
||||
pom_file.push(Path::new("pom.xml"));
|
||||
|
||||
let pom_file = fs::read_to_string(pom_file).map_err(|e| e.to_string())?;
|
||||
let root = get_pom(pom_file).map_err(|e| e.to_string())?;
|
||||
|
||||
let modules= root.modules
|
||||
.iter()
|
||||
.map(|module| read_module_pom(project_dir, module))
|
||||
.collect();
|
||||
|
||||
Ok(Project {
|
||||
root,
|
||||
modules,
|
||||
})
|
||||
}
|
||||
|
||||
fn read_module_pom(project_dir: &Path, module: &String) -> Pom {
|
||||
let mut module_file = project_dir.to_path_buf();
|
||||
module_file.push(Path::new(module));
|
||||
module_file.push(Path::new("pom.xml"));
|
||||
let module_pom = fs::read_to_string(module_file)
|
||||
.expect(format!("Cannot read file {}", module).as_str());
|
||||
get_pom(module_pom).expect(format!("Cannot create module pom {}", module).as_str())
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Project {
|
||||
pub root: Pom,
|
||||
pub modules: Vec<Pom>,
|
||||
}
|
||||
|
|
@ -28,8 +28,8 @@ fn test_pom_parser_is_correct() {
|
|||
assert_eq!(Some("1.0".to_string()), objenesis.version);
|
||||
|
||||
assert_eq!(2, pom.modules.len());
|
||||
assert_eq!("a", pom.modules[0]);
|
||||
assert_eq!("b", pom.modules[1]);
|
||||
assert_eq!("a", pom.module_names[0]);
|
||||
assert_eq!("b", pom.module_names[1]);
|
||||
|
||||
assert_eq!(1, pom.dependency_management.len());
|
||||
let hamcrest = &pom.dependency_management[0];
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
use std::path::Path;
|
||||
use undeepend::maven::project_parser::parse_project;
|
||||
use undeepend::maven::project::parse_project;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue