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 std::path::Path;
|
||||||
use undeepend::maven::project_parser::parse_project;
|
use undeepend::maven::project::parse_project;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let project = parse_project(Path::new("tests/maven/resources/sample_project")).unwrap();
|
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;
|
||||||
pub mod pom_view;
|
pub mod pom_view;
|
||||||
pub mod pom_parser;
|
pub mod pom_parser;
|
||||||
pub mod project_parser;
|
pub mod project;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
/// The Maven variant to parse poms
|
/// The Maven variant to parse poms
|
||||||
/// These structs is directly modelled after the XML because that is what strong-xml plugin requires
|
/// 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 dependencies: Vec<Dependency>,
|
||||||
pub dependency_management: Vec<Dependency>,
|
pub dependency_management: Vec<Dependency>,
|
||||||
pub properties: HashMap<String, String>,
|
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)]
|
#[derive(PartialEq, Debug)]
|
||||||
|
|
@ -42,13 +49,4 @@ pub struct Dependency {
|
||||||
pub group_id: String,
|
pub group_id: String,
|
||||||
pub artifact_id: String,
|
pub artifact_id: String,
|
||||||
pub version: Option<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::SaxError;
|
||||||
use crate::xml::dom_parser::{Node, get_document};
|
use crate::xml::dom_parser::{Node, get_document};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub fn get_pom(xml: impl Into<String>) -> Result<Pom, SaxError> {
|
pub fn get_pom(xml: impl Into<String>) -> Result<Pom, SaxError> {
|
||||||
let mut group_id = None;
|
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 dependencies = vec![];
|
||||||
let mut dependency_management = vec![];
|
let mut dependency_management = vec![];
|
||||||
let mut properties = HashMap::new(); // useless assignment...
|
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 {
|
for child in get_document(xml.into().as_str())?.root.children {
|
||||||
match child.name.as_str() {
|
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),
|
"dependencies" => dependencies = get_dependencies(child),
|
||||||
"dependencyManagement" => dependency_management = get_dependency_mgmt(child),
|
"dependencyManagement" => dependency_management = get_dependency_mgmt(child),
|
||||||
"properties" => properties = get_properties(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,
|
dependencies,
|
||||||
dependency_management,
|
dependency_management,
|
||||||
properties,
|
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!(Some("1.0".to_string()), objenesis.version);
|
||||||
|
|
||||||
assert_eq!(2, pom.modules.len());
|
assert_eq!(2, pom.modules.len());
|
||||||
assert_eq!("a", pom.modules[0]);
|
assert_eq!("a", pom.module_names[0]);
|
||||||
assert_eq!("b", pom.modules[1]);
|
assert_eq!("b", pom.module_names[1]);
|
||||||
|
|
||||||
assert_eq!(1, pom.dependency_management.len());
|
assert_eq!(1, pom.dependency_management.len());
|
||||||
let hamcrest = &pom.dependency_management[0];
|
let hamcrest = &pom.dependency_management[0];
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
use std::path::Path;
|
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