1use std::{
2 collections::BTreeMap,
3 path::{Path, PathBuf},
4};
5
6use cargo_toml::Manifest;
7use lazy_regex::{Lazy, Regex, lazy_regex};
8
9use crate::Error;
10
11static CRATE: Lazy<Regex> = lazy_regex!(r"^.+update rust crate (?P<crate>[\w-]+).+$");
16
17#[derive(Debug, Clone, Default)]
24pub struct RustPackage {
25 pub root: String,
26 pub dependencies: Vec<String>,
27}
28
29impl RustPackage {
30 fn new(root: String, dependencies: Vec<String>) -> RustPackage {
31 RustPackage { root, dependencies }
32 }
33
34 pub fn is_related_to_package(&self, subject: &str, files_in_commit: Vec<PathBuf>) -> bool {
57 if self.is_update_to_package_dependency(subject) {
58 if !log::log_enabled!(log::Level::Debug) {
59 log::debug!("Commit is an update to a dependency");
60 }
61 if !log::log_enabled!(log::Level::Trace) {
62 log::trace!("Commit is an update to a dependency ({subject})");
63 }
64 return true;
65 }
66
67 if self.is_commit_to_package_file(files_in_commit) {
68 if !log::log_enabled!(log::Level::Debug) {
69 log::debug!("File in package directory tree");
70 }
71 if !log::log_enabled!(log::Level::Trace) {
72 log::trace!("File in package directory tree ({})", self.root);
73 }
74 return true;
75 }
76
77 log::trace!(
78 "Commit is not related to the {} package",
79 self.root
80 .split('/')
81 .next_back()
82 .unwrap_or("***not found***")
83 );
84 false
85 }
86
87 fn is_update_to_package_dependency(&self, subject: &str) -> bool {
88 if let Some(caps) = CRATE.captures(subject) {
89 self.dependencies.iter().any(|d| *d == caps[1])
90 } else {
91 false
92 }
93 }
94
95 fn is_commit_to_package_file(&self, files_in_commit: Vec<PathBuf>) -> bool {
96 let filter = &self.root;
97
98 for file in files_in_commit {
99 log::debug!("Test `{}`", file.display());
100
101 if file.display().to_string().starts_with(filter) {
102 return true;
103 }
104 }
105
106 false
107 }
108}
109
110#[derive(Debug, Clone)]
119pub struct RustPackages {
120 pub packages_by_name: BTreeMap<String, RustPackage>,
122}
123
124impl RustPackages {
125 pub fn new(root: &Path) -> Result<RustPackages, Error> {
129 log::debug!("getting the rust packages in the repository");
130 let mut packages = BTreeMap::new();
131 log::debug!("Starting from the root `{}`", root.display());
132
133 let ws_toml = root.join("Cargo.toml");
135 let ws = Manifest::from_path(ws_toml)?;
136 if let Some(workspace) = ws.workspace {
137 for member in workspace.members {
138 let pkg_root = root.join(&member);
139 let pkg_toml = pkg_root.join("Cargo.toml");
140 let pkg_manifest = Manifest::from_path(pkg_toml)?;
141
142 if let Some(pkg) = pkg_manifest.package {
144 let mut dependencies: Vec<String> =
145 pkg_manifest.dependencies.keys().cloned().collect();
146 dependencies
147 .append(&mut pkg_manifest.dev_dependencies.keys().cloned().collect());
148 dependencies
149 .append(&mut pkg_manifest.build_dependencies.keys().cloned().collect());
150
151 let rust_package = RustPackage::new(member, dependencies);
152
153 packages.insert(pkg.name, rust_package);
154 }
155 }
156 }
157
158 Ok(RustPackages {
159 packages_by_name: packages,
160 })
161 }
162}