Skip to main content

package_parser/pkgs/dotnet/
nuget_central.rs

1use std::path::Path;
2
3use packageurl::PackageUrl;
4use crate::types::{DependentPackage, Package};
5use serde::Deserialize;
6
7use crate::{error::SourcePkgError, PackageManifest};
8
9#[derive(Debug, Deserialize)]
10struct Project {
11    #[serde(rename = "ItemGroup")]
12    item_group: ItemGroup,
13}
14
15#[derive(Debug, Deserialize)]
16struct ItemGroup {
17    #[serde(rename = "PackageVersion", default)]
18    items: Vec<PackageVersion>,
19}
20
21#[derive(Debug, Deserialize)]
22struct PackageVersion {
23    #[serde(rename = "Include")]
24    name: String,
25    #[serde(rename = "Version")]
26    version: String,
27}
28
29pub struct NuGetCentral;
30
31impl NuGetCentral {
32    pub fn new() -> Self {
33        Self
34    }
35
36    async fn parse(path: impl AsRef<Path>) -> Result<Package, SourcePkgError> {
37        let content = tokio::fs::read_to_string(path).await?;
38        let project: Project = quick_xml::de::from_str(&content)?;
39
40        let mut dependencies = vec![];
41
42        for item in project.item_group.items {
43            dependencies.push(DependentPackage {
44                purl: PackageUrl::new("nuget", item.name)
45                    .unwrap()
46                    .with_version(&item.version)
47                    .to_string(),
48                requirement: item.version,
49                is_resolved: true,
50                is_optional: false,
51                is_runtime: true,
52                ..Default::default()
53            });
54        }
55
56        Ok(Package {
57            dependencies,
58            ..Default::default()
59        })
60    }
61}
62
63#[async_trait::async_trait]
64impl PackageManifest for NuGetCentral {
65    fn get_name(&self) -> String {
66        "nuget".into()
67    }
68
69    async fn recognize(&self, path: &Path) -> Result<Package, SourcePkgError> {
70        let root = Self::parse(path).await?;
71        Ok(root)
72    }
73
74    fn file_name_patterns(&self) -> &'static [&'static str] {
75        &[
76            "Directory.packages.props",
77            "Directory.Packages.props",
78            "directory.packages.props",
79            "directory.Packages.props",
80        ]
81    }
82}
83
84#[cfg(test)]
85mod test {
86    use super::*;
87
88    #[tokio::test]
89    async fn central() {
90        let path = Path::new(concat!(
91            env!("CARGO_MANIFEST_DIR"),
92            "/testdata/nuget/Directory.packages.props"
93        ));
94        let package = NuGetCentral::new().recognize(path).await.unwrap();
95        dbg!(package);
96    }
97}