Skip to main content

package_parser/pkgs/python/
pyconda.rs

1use serde_yaml::from_str;
2use serde_yaml::Value;
3
4use crate::error::SourcePkgError;
5use crate::pkgs::common::model::{Package, PackageManifest};
6
7use crate::pkgs::pyrequirements::PyRequirements;
8
9use std::fs::File;
10use std::io::Read;
11use std::path::Path;
12
13pub struct PyConda {}
14
15impl PyConda {
16    pub fn new() -> Self {
17        Self {}
18    }
19
20    fn convert_to_pure_yaml(content: &str) -> String {
21        let mut newlines = vec![];
22        for line in content.lines() {
23            if line.starts_with('{') {
24                continue;
25            }
26            newlines.push(line);
27        }
28
29        newlines.join("\n")
30    }
31
32    fn parse(path: impl AsRef<Path>) -> Result<Package, SourcePkgError> {
33        let mut file = File::open(path)?;
34        let mut content = String::new();
35        file.read_to_string(&mut content)?;
36        let content = Self::convert_to_pure_yaml(&content);
37        let root: Value = from_str(&content)?;
38        let package_name = &root["package"]["name"].as_str();
39        let package_license = &root["about"]["license"].as_str();
40        let requirements_section = &root["requirements"]["run"].as_sequence().map(|seq| {
41            let mut requirements = vec![];
42            for s in seq {
43                if s.is_string() {
44                    requirements.push(s.as_str().unwrap());
45                }
46            }
47
48            requirements.join("\n")
49        });
50
51        let requirements = match requirements_section {
52            Some(requirements) => requirements.to_string(),
53            None => "".to_string(),
54        };
55
56        let requirements =
57            PyRequirements::parse_requirement_content(&requirements).unwrap_or_default();
58
59        let package = Package {
60            name: package_name.unwrap_or("").to_string(),
61            declared_license: package_license.unwrap_or("").to_string(),
62            dependencies: requirements,
63            ..Default::default()
64        };
65
66        Ok(package)
67    }
68}
69
70#[async_trait::async_trait]
71impl PackageManifest for PyConda {
72    fn get_name(&self) -> String {
73        "pypi".to_string()
74    }
75
76    async fn recognize(&self, path: &Path) -> Result<Package, SourcePkgError> {
77        Self::parse(path)
78    }
79
80    fn file_name_patterns(&self) -> &'static [&'static str] {
81        &["conda.yaml", "conda*.yaml"]
82    }
83}
84
85