1use crate::package::{Package, Version};
2use anyhow::{Context, Result};
3use pubgrub::range::Range;
4use serde::{Deserialize, Serialize};
5use std::str::FromStr;
6
7#[derive(Default, Deserialize, Serialize)]
8#[serde(rename = "project")]
9pub struct Pom {
10 packaging: Option<String>,
11 #[serde(default)]
12 dependencies: Dependencies,
13}
14
15impl Pom {
16 pub fn packaging(&self) -> &str {
17 if let Some(s) = self.packaging.as_deref() {
18 s
19 } else {
20 "jar"
21 }
22 }
23
24 pub fn dependencies(&self) -> &[Dependency] {
25 &self.dependencies.dependencies
26 }
27}
28
29#[derive(Default, Deserialize, Serialize)]
30#[serde(rename = "dependencies")]
31struct Dependencies {
32 #[serde(rename = "$value")]
33 #[serde(default)]
34 dependencies: Vec<Dependency>,
35}
36
37#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
38#[serde(rename = "dependency")]
39pub struct Dependency {
40 #[serde(rename = "$unflatten=groupId")]
41 group: String,
42 #[serde(rename = "$unflatten=artifactId")]
43 name: String,
44 #[serde(rename = "$unflatten=version")]
45 version: String,
46 #[serde(rename = "$unflatten=scope")]
47 scope: Option<String>,
48}
49
50impl Dependency {
51 pub fn package(&self) -> Package {
52 Package {
53 group: self.group.clone(),
54 name: self.name.clone(),
55 }
56 }
57
58 pub fn scope(&self) -> Option<&str> {
59 self.scope.as_deref()
60 }
61
62 pub fn range(&self) -> Result<Range<Version>> {
63 crate::range::range(&self.version)
64 }
65}
66
67impl FromStr for Dependency {
68 type Err = anyhow::Error;
69
70 fn from_str(dep: &str) -> Result<Self> {
71 let (group, rest) = dep.split_once(':').context("invalid dep")?;
72 let (name, version) = rest.split_once(':').context("invalid dep")?;
73 Ok(Self {
74 group: group.into(),
75 name: name.into(),
76 version: version.into(),
77 scope: None,
78 })
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85 use anyhow::Result;
86
87 #[test]
88 fn test_dep() -> Result<()> {
89 let dep = r#"
90 <dependency>
91 <groupId>group</groupId>
92 <artifactId>name</artifactId>
93 <version>1.0.0-alpha</version>
94 </dependency>"#;
95 let dep: Dependency = quick_xml::de::from_str(dep)?;
96 assert_eq!(dep.package().group, "group");
97 assert_eq!(dep.package().name, "name");
98 Ok(())
100 }
101
102 #[test]
103 fn test_pom() -> Result<()> {
104 let pom = r#"
105 <project>
106 <dependencies>
107 <dependency>
108 <groupId>group</groupId>
109 <artifactId>name</artifactId>
110 <version>0.0.1</version>
111 </dependency>
112 </dependencies>
113 </project>"#;
114 let pom: Pom = quick_xml::de::from_str(pom)?;
115 let deps = pom.dependencies();
116 assert_eq!(deps.len(), 1);
117 assert_eq!(deps[0].package().group, "group");
118 assert_eq!(deps[0].package().name, "name");
119 Ok(())
121 }
122
123 #[test]
124 fn test_pom2() -> Result<()> {
125 let pom = r#"
126 <project>
127 <dependencies/>
128 </project>"#;
129 let pom: Pom = quick_xml::de::from_str(pom)?;
130 let deps = pom.dependencies();
131 assert!(deps.is_empty());
132 Ok(())
133 }
134}