Skip to main content

package_parser/pkgs/common/
model.rs

1use std::path::{Path, PathBuf};
2
3use anyhow::Result;
4use fnmatch_regex::glob_to_regex;
5use packageurl::PackageUrl;
6pub use crate::types::{DependentPackage, Package, Party};
7use serde_json::Value;
8
9use crate::error::SourcePkgError;
10
11pub fn get_filename_as_string(path: impl AsRef<Path>) -> Option<String> {
12    let location = path.as_ref();
13    match location.file_name() {
14        Some(name) => {
15            let name = name.to_os_string();
16            let name = name.to_string_lossy();
17            Some(name.to_string())
18        }
19        None => None,
20    }
21}
22
23pub trait BaseModel {
24    fn to_json(&self) -> Value;
25}
26
27pub fn is_manifest_default(path: &Path, patterns: &Vec<String>, extensions: &Vec<String>) -> bool {
28    let location = path;
29
30    let filename = match get_filename_as_string(location) {
31        Some(filename) => filename,
32        None => return false,
33    };
34
35    for pattern in patterns {
36        match glob_to_regex(&pattern.to_ascii_lowercase()) {
37            Ok(regex) => {
38                if regex.is_match(&filename.to_ascii_lowercase()) {
39                    return true;
40                }
41            }
42            Err(err) => {
43                println!("{}", err);
44            }
45        }
46    }
47
48    for extension in extensions {
49        match glob_to_regex(&extension.to_ascii_lowercase()) {
50            Ok(regex) => {
51                if regex.is_match(&filename.to_ascii_lowercase()) {
52                    return true;
53                }
54            }
55            Err(err) => {
56                println!("{}", err);
57            }
58        }
59    }
60
61    false
62}
63
64#[derive(Debug, Default)]
65pub struct RecognizeContext {
66    /// Prefix of the current file.
67    ///
68    /// A file should not reference any other file outside of its prefix.
69    pub prefix: PathBuf,
70}
71
72#[async_trait::async_trait]
73pub trait PackageManifest: Sync {
74    fn get_name(&self) -> String;
75
76    fn get_identifier(&self) -> String {
77        self.get_name()
78    }
79
80    fn file_name_patterns(&self) -> &'static [&'static str];
81
82    async fn recognize(&self, path: &Path) -> Result<Package, SourcePkgError>;
83
84    async fn recognize_with_config(
85        &self,
86        path: &Path,
87        _context: &RecognizeContext,
88    ) -> Result<Package, SourcePkgError> {
89        self.recognize(path).await
90    }
91}
92
93pub struct DependentPackageBuilder {
94    ty: String,
95    name: String,
96    inner: DependentPackage,
97}
98
99impl DependentPackageBuilder {
100    pub fn new(
101        ty: impl Into<String>,
102        name: impl Into<String>,
103        requirement: impl Into<String>,
104        scope: impl Into<String>,
105    ) -> Self {
106        Self {
107            ty: ty.into(),
108            name: name.into(),
109            inner: DependentPackage {
110                requirement: requirement.into(),
111                scope: scope.into(),
112                ..Default::default()
113            },
114        }
115    }
116
117    pub fn with_is_runtime(mut self, is_runtime: bool) -> Self {
118        self.inner.is_runtime = is_runtime;
119        self
120    }
121
122    pub fn with_is_optional(mut self, is_optional: bool) -> Self {
123        self.inner.is_optional = is_optional;
124        self
125    }
126
127    pub fn with_is_resolved(mut self, is_resolved: bool) -> Self {
128        self.inner.is_resolved = is_resolved;
129        self
130    }
131
132    pub fn with_parents(mut self, parents: impl IntoIterator<Item = String>) -> Self {
133        self.inner.parents = parents.into_iter().collect();
134        self
135    }
136
137    pub fn build(mut self) -> Result<DependentPackage> {
138        self.inner.purl = PackageUrl::new(self.ty, self.name)?
139            .add_qualifier("is_runtime", self.inner.is_runtime.to_string())?
140            .add_qualifier("is_optional", self.inner.is_optional.to_string())?
141            .to_string();
142
143        Ok(self.inner)
144    }
145}