1use crate::{Dependency, RetrievedDependency};
5use serde::{Deserialize, Serialize};
6use tracing::instrument;
7
8#[derive(Serialize, Deserialize, Debug, Default, Clone)]
12pub struct LicRc {
13 pub licenses: LicRcLicenses,
15 pub dependencies: LicRcDependencies,
17 pub behavior: LicRcBehavior,
19}
20
21#[cfg(feature = "licrc-from-file")]
23#[derive(Debug, thiserror::Error)]
24pub enum Error {
25 #[error("Error trying to open and read the .licrc file: {0}")]
27 Io(#[from] std::io::Error),
28 #[error("Error trying to parse the .licrc file: {0}")]
30 Toml(#[from] toml::de::Error),
31}
32
33#[cfg(feature = "licrc-from-file")]
34impl LicRc {
35 #[instrument(skip(relative_path))]
38 pub fn from_relative_path(relative_path: impl AsRef<std::path::Path>) -> Result<Self, Error> {
39 let licrc_path = std::env::current_dir()?.join(relative_path);
40 let licrc_content = std::fs::read_to_string(licrc_path)?;
41 let licrc = toml::from_str(&licrc_content)?;
42 Ok(licrc)
43 }
44}
45
46impl LicRc {
47 pub fn is_ignored(&self, dependency: &mut RetrievedDependency) -> bool {
50 if self
52 .dependencies
53 .ignored
54 .as_ref()
55 .unwrap_or(&vec![])
56 .contains(&dependency.name)
57 {
58 dependency.is_ignored = true;
59 return true;
60 }
61
62 if self.dependencies.ignore_dev_dependencies && dependency.is_dev.unwrap_or(false) {
64 dependency.is_ignored = true;
65 return true;
66 }
67
68 if self.dependencies.ignore_optional_dependencies && dependency.is_optional.unwrap_or(false)
70 {
71 dependency.is_ignored = true;
72 return true;
73 }
74 false
75 }
76
77 pub fn filter_dependencies_before_retrieval(&self, dependency: &Dependency) -> bool {
79 let is_dev = dependency.is_dev.unwrap_or_default();
80 let is_optional = dependency.is_optional.unwrap_or_default();
81
82 if self.behavior.do_not_show_dev_dependencies && is_dev {
83 return false;
84 }
85 if self.behavior.do_not_show_optional_dependencies && is_optional {
86 return false;
87 }
88
89 let is_ignored = self
90 .dependencies
91 .ignored
92 .as_ref()
93 .unwrap_or(&vec![])
94 .contains(&dependency.name);
95
96 if self.behavior.do_not_show_ignored_dependencies {
97 if is_ignored {
98 return false;
99 }
100 if self.dependencies.ignore_dev_dependencies && is_dev {
101 return false;
102 }
103 if self.dependencies.ignore_optional_dependencies && is_optional {
104 return false;
105 }
106 }
107
108 true
109 }
110
111 #[instrument(skip(self))]
115 pub fn validate(&self, dependency: &mut RetrievedDependency) {
116 dependency.validated = true;
117 if self.is_ignored(dependency) {
119 tracing::debug!(dependency = ?dependency, "Dependency has been ignored");
120 return;
121 }
122 if !dependency.is_valid {
124 tracing::debug!(dependency = ?dependency, "Dependency is invalid");
125 return;
126 }
127
128 dependency.licenses.clone().map_or_else(
129 || {
130 tracing::error!("Licenses are None!! At this point, this shouldn't happen. Check out the dependency validation logic");
131 },
132 |licenses| {
133 for lic in &licenses {
134 if let Some(accepted) = self.licenses.accepted.as_ref() {
135 if !accepted.contains(lic) {
136 make_invalid(dependency, lic);
137 }
138 } else if let Some(unaccepted) = self.licenses.unaccepted.as_ref() {
139 if unaccepted.contains(lic) {
140 make_invalid(dependency, lic);
141 }
142 }
143 }
144 },
145 );
146 }
147}
148
149#[instrument]
151fn make_invalid(dependency: &mut RetrievedDependency, license: &str) {
152 tracing::debug!(
153 ?dependency,
154 license,
155 "No compliant dependency marked as invalid"
156 );
157 dependency.is_valid = false;
158 if dependency.error.is_none() {
160 dependency.error = Some("Not compliant".to_string());
161 }
162}
163
164#[derive(Serialize, Deserialize, Debug, Default, Clone)]
166pub struct LicRcLicenses {
167 pub accepted: Option<Vec<String>>,
169 pub unaccepted: Option<Vec<String>>,
171}
172
173#[derive(Serialize, Deserialize, Debug, Default, Clone)]
175pub struct LicRcDependencies {
176 pub ignored: Option<Vec<String>>,
180 #[serde(default)]
182 pub ignore_dev_dependencies: bool,
183 #[serde(default)]
185 pub ignore_optional_dependencies: bool,
186}
187
188#[allow(clippy::struct_excessive_bools)]
191#[derive(Serialize, Deserialize, Debug, Default, Clone)]
192pub struct LicRcBehavior {
193 pub run_only_on_dependency_modification: Option<bool>,
196 #[serde(default)]
198 pub do_not_block_pr: bool,
199 pub retriever_buffer_size: Option<usize>,
203 #[serde(default)]
205 pub do_not_show_ignored_dependencies: bool,
206 #[serde(default)]
208 pub do_not_show_dev_dependencies: bool,
209 #[serde(default)]
211 pub do_not_show_optional_dependencies: bool,
212}