mvn/
pom.rs

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        //assert_eq!(dep.version()?.to_string(), "1.0.0-alpha");
99        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        //assert_eq!(deps[0].version()?.to_string(), "0.0.1");
120        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}