Skip to main content

thirdpass_core/extension/
common.rs

1use anyhow::Result;
2
3#[derive(
4    Debug, Clone, Hash, Eq, PartialEq, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
5)]
6pub struct VersionError(String);
7
8impl VersionError {
9    pub fn from_missing_version() -> Self {
10        Self("Missing version number".to_string())
11    }
12
13    pub fn from_parse_error(raw_version_number: &str) -> Self {
14        Self(format!("Version parse error: {}", raw_version_number))
15    }
16
17    pub fn message(&self) -> String {
18        self.0.clone()
19    }
20}
21
22pub type VersionParseResult = std::result::Result<String, VersionError>;
23
24/// A dependency as specified within a dependencies definition file.
25#[derive(
26    Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
27)]
28pub struct Dependency {
29    pub name: String,
30    pub version: VersionParseResult,
31}
32
33pub trait DependenciesCollection: Sized {
34    fn registry_host_name(&self) -> &String;
35    fn dependencies(&self) -> &Vec<Dependency>;
36}
37
38/// Package dependencies found by querying a registry.
39#[derive(Clone, Debug, Hash, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
40pub struct PackageDependencies {
41    // Package version (included incase version not given as an argument).
42    pub package_version: VersionParseResult,
43
44    /// Dependencies registry host name.
45    pub registry_host_name: String,
46
47    /// Dependencies specified within the dependencies specification file.
48    pub dependencies: Vec<Dependency>,
49}
50
51impl DependenciesCollection for PackageDependencies {
52    fn registry_host_name(&self) -> &String {
53        &self.registry_host_name
54    }
55    fn dependencies(&self) -> &Vec<Dependency> {
56        &self.dependencies
57    }
58}
59
60/// A dependencies specification file found from inspecting the local filesystem.
61#[derive(Clone, Debug, Hash, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
62pub struct FileDefinedDependencies {
63    /// Absolute file path for dependencies specification file.
64    pub path: std::path::PathBuf,
65
66    /// Dependencies registry host name.
67    pub registry_host_name: String,
68
69    /// Dependencies specified within the dependencies specification file.
70    pub dependencies: Vec<Dependency>,
71}
72
73impl DependenciesCollection for FileDefinedDependencies {
74    fn registry_host_name(&self) -> &String {
75        &self.registry_host_name
76    }
77    fn dependencies(&self) -> &Vec<Dependency> {
78        &self.dependencies
79    }
80}
81
82#[derive(Debug, Clone, Hash, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
83pub struct RegistryPackageMetadata {
84    pub registry_host_name: String,
85    pub human_url: String,
86    pub artifact_url: String,
87    // True if this registry is the primary registry, otherwise false.
88    pub is_primary: bool,
89    // Included here incase package version was not given but found.
90    pub package_version: String,
91}
92
93/// Policy for selecting automatic review target files.
94#[derive(Debug, Clone, Default, Hash, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
95pub struct ReviewTargetPolicy {
96    /// Exact package-relative paths to exclude from automatic target selection.
97    pub excluded_exact_paths: Vec<String>,
98}
99
100impl ReviewTargetPolicy {
101    /// Return true when this policy excludes the exact package-relative path.
102    pub fn excludes_exact_path(&self, package_relative_path: &str) -> bool {
103        self.excluded_exact_paths
104            .iter()
105            .any(|excluded_path| excluded_path == package_relative_path)
106    }
107
108    /// Return true when this policy excludes the package-relative path.
109    pub fn excludes_path(&self, package_relative_path: &std::path::Path) -> bool {
110        self.excludes_exact_path(&package_relative_path_string(package_relative_path))
111    }
112}
113
114fn package_relative_path_string(package_relative_path: &std::path::Path) -> String {
115    if package_relative_path.as_os_str().is_empty() {
116        return ".".to_string();
117    }
118
119    package_relative_path
120        .iter()
121        .map(|component| component.to_string_lossy().into_owned())
122        .collect::<Vec<_>>()
123        .join("/")
124}
125
126pub trait FromLib: Extension + Send + Sync {
127    /// Initialize extension from a library.
128    fn new() -> Self
129    where
130        Self: Sized;
131}
132
133pub trait FromProcess: Extension + Send + Sync {
134    /// Initialize extension from a process.
135    fn from_process(
136        process_path: &std::path::PathBuf,
137        extension_config_path: &std::path::PathBuf,
138    ) -> Result<Self>
139    where
140        Self: Sized;
141}
142
143pub trait Extension: Send + Sync {
144    // Returns extension short name.
145    fn name(&self) -> String;
146
147    // Returns supported registries host names.
148    fn registries(&self) -> Vec<String>;
149
150    /// Return automatic review-target selection policy for this extension.
151    fn review_target_policy(&self) -> ReviewTargetPolicy {
152        ReviewTargetPolicy::default()
153    }
154
155    /// Identify specific package dependencies.
156    fn identify_package_dependencies(
157        &self,
158        package_name: &str,
159        package_version: &Option<&str>,
160        extension_args: &Vec<String>,
161    ) -> Result<Vec<PackageDependencies>>;
162
163    /// Identify file defined dependencies.
164    fn identify_file_defined_dependencies(
165        &self,
166        working_directory: &std::path::PathBuf,
167        extension_args: &Vec<String>,
168    ) -> Result<Vec<FileDefinedDependencies>>;
169
170    /// Query package registries for package metadata.
171    fn registries_package_metadata(
172        &self,
173        package_name: &str,
174        package_version: &Option<&str>,
175    ) -> Result<Vec<RegistryPackageMetadata>>;
176}