package_parser/pkgs/common/
model.rs1use 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 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}