diff --git a/src/lib.rs b/src/lib.rs index 00d97577..3335e38b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -263,6 +263,17 @@ impl Krate { } }) } + + /// Returns the normalized source URL + pub(crate) fn normalized_source_url(&self) -> Option { + self.source.as_ref().map(|source| { + let mut url = source.url().clone(); + url.set_query(None); + url.set_fragment(None); + crate::sources::normalize_url(&mut url); + url + }) + } } impl fmt::Display for Krate { diff --git a/src/licenses.rs b/src/licenses.rs index 8af1e84e..29218963 100644 --- a/src/licenses.rs +++ b/src/licenses.rs @@ -282,13 +282,18 @@ pub fn check( let mut pack = Pack::with_kid(Check::Licenses, krate_lic_nfo.krate.id.clone()); // If the user has set this, check if it's a private workspace - // crate and just print out a help message that we skipped it + // crate or a crate from a private registry and just print out + // a help message that we skipped it if ctx.cfg.private.ignore - && ctx - .krates - .workspace_members() - .any(|wm| wm.id == krate_lic_nfo.krate.id) - && krate_lic_nfo.krate.is_private(&private_registries) + && (krate_lic_nfo + .krate + .normalized_source_url() + .map_or(false, |source| ctx.cfg.ignore_sources.contains(&source)) + || (ctx + .krates + .workspace_members() + .any(|wm| wm.id == krate_lic_nfo.krate.id) + && krate_lic_nfo.krate.is_private(&private_registries))) { pack.push(diags::SkippedPrivateWorkspaceCrate { krate: krate_lic_nfo.krate, diff --git a/src/licenses/cfg.rs b/src/licenses/cfg.rs index 6390374d..ffeb15d0 100644 --- a/src/licenses/cfg.rs +++ b/src/licenses/cfg.rs @@ -65,6 +65,10 @@ pub struct Private { /// only published to private registries #[serde(default)] pub ignore: bool, + /// One or more URLs to private registries, if a crate comes from one + /// of these registries, the crate will not have its license checked + #[serde(default)] + pub ignore_sources: Vec>, /// One or more private registries that you might publish crates to, if /// a crate is only published to private registries, and ignore is true /// the crate will not have its license checked @@ -198,6 +202,24 @@ impl crate::cfg::UnvalidatedConfig for Config { fn validate(self, cfg_file: FileId, diags: &mut Vec) -> Self::ValidCfg { use rayon::prelude::*; + let mut ignore_sources = Vec::with_capacity(self.private.ignore_sources.len()); + for aurl in &self.private.ignore_sources { + match url::Url::parse(aurl.as_ref()) { + Ok(mut url) => { + crate::sources::normalize_url(&mut url); + ignore_sources.push(url); + } + Err(pe) => { + diags.push( + Diagnostic::error() + .with_message("failed to parse url") + .with_labels(vec![Label::primary(cfg_file, aurl.span.clone()) + .with_message(pe.to_string())]), + ); + } + } + } + let mut parse_license = |ls: &Spanned, v: &mut Vec| { match spdx::Licensee::parse(ls.as_ref()) { Ok(licensee) => { @@ -306,6 +328,7 @@ impl crate::cfg::UnvalidatedConfig for Config { exceptions, denied, allowed, + ignore_sources, } } } @@ -344,6 +367,7 @@ pub struct ValidConfig { pub allowed: Vec, pub clarifications: Vec, pub exceptions: Vec, + pub ignore_sources: Vec, } #[cfg(test)] diff --git a/src/sources.rs b/src/sources.rs index 4b75ffac..fab86dc9 100644 --- a/src/sources.rs +++ b/src/sources.rs @@ -214,7 +214,7 @@ pub fn check(ctx: crate::CheckCtx<'_, ValidConfig>, mut sink: ErrorSink) { } } -fn normalize_url(url: &mut Url) { +pub(crate) fn normalize_url(url: &mut Url) { // Normalizes the URL so that different representations can be compared to each other. // At the moment we just remove a tailing `.git` but there are more possible optimisations. // See https://github.com/rust-lang/cargo/blob/1f6c6bd5e7bbdf596f7e88e6db347af5268ab113/src/cargo/util/canonical_url.rs#L31-L57