Skip to main content

package_parser/
lib.rs

1#![allow(clippy::new_without_default)]
2
3pub mod error;
4pub mod helper;
5pub mod pkgs;
6pub mod types;
7
8use globset::{Glob, GlobSet, GlobSetBuilder};
9pub use pkgs::common::model::{DependentPackage, Package, PackageManifest};
10use std::collections::HashMap;
11use std::path::Path;
12use std::sync::Arc;
13use crate::types::SupportedType;
14
15
16#[derive(Clone)]
17pub struct Scanner {
18
19    scanners: Vec<Arc<dyn PackageManifest + Send + Sync>>,
20    types: Vec<SupportedType>,
21
22    glob_index_to_scanner_index: HashMap<usize, usize>,
23    glob_set: GlobSet,
24}
25
26impl Scanner {
27    pub fn new() -> Self {
28        let scanners = pkgs::create_scanners();
29
30        let mut glob_index_to_scanner_index = HashMap::new();
31        let mut glob_set = GlobSetBuilder::new();
32        let mut current_glob_index = 0usize;
33
34        let mut supported_types = vec![];
35        for (index, scanner) in scanners.iter().enumerate() {
36            let supported_type = SupportedType {
37                name: scanner.get_identifier(),
38                filenames: scanner
39                    .file_name_patterns()
40                    .iter()
41                    .map(|s| s.to_string())
42                    .collect(),
43                patterns: vec![],
44            };
45            supported_types.push(supported_type);
46
47            for pat in scanner.file_name_patterns() {
48                let glob = Glob::new(pat).expect("Failed to compile pattern");
49                glob_set.add(glob);
50                glob_index_to_scanner_index.insert(current_glob_index, index);
51                current_glob_index += 1;
52            }
53        }
54
55        let glob_set = glob_set.build().expect("Failed to build glob set");
56
57        Self {
58            scanners,
59            types: supported_types,
60
61            glob_index_to_scanner_index,
62            glob_set,
63        }
64    }
65
66    pub async fn scan(
67        &self,
68        path: impl AsRef<Path>,
69        prefix: impl AsRef<Path>,
70    ) -> Result<(String, Package), error::SourcePkgError> {
71        let location = path.as_ref();
72        let prefix = prefix.as_ref();
73
74        if let Some(match_idx) = self
75            .glob_set
76            .matches(
77                location
78                    .file_name()
79                    .ok_or(error::SourcePkgError::GenericsError(
80                        "Invalid file name ending in '..'",
81                    ))?,
82            )
83            .first()
84        {
85            let scanner_idx = self.glob_index_to_scanner_index[match_idx];
86            let scanner = &self.scanners[scanner_idx];
87            let ctx = pkgs::RecognizeContext {
88                prefix: prefix.to_path_buf(),
89            };
90
91            return match scanner.recognize_with_config(location, &ctx).await {
92                Ok(manifest) => Ok((scanner.get_name(), manifest)),
93                Err(e) => Err(e),
94            };
95        }
96
97        Err(error::SourcePkgError::NotSupported)
98    }
99
100    pub fn supported_types(&self) -> &[SupportedType] {
101        &self.types
102    }
103}