Skip to content

Commit

Permalink
Cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
Jake-Shadle committed Sep 3, 2023
1 parent bedf0d1 commit 9867908
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 62 deletions.
46 changes: 9 additions & 37 deletions src/cargo-deny/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,44 +171,9 @@ impl ValidConfig {
}
};

let mut cfg: Config = toml::from_str(&cfg_contents)
let cfg: Config = toml::from_str(&cfg_contents)
.with_context(|| format!("failed to deserialize config from '{cfg_path}'"))?;

// Allow for project-local exceptions. Relevant in corporate environments.
// https://github.com/EmbarkStudios/cargo-deny/issues/541
//
// This isn't the cleanest, but cfg.licenses isn't mutable, so appending/extending the Vec
// isn't possible. Similarly, the various Config/ValidConfig structs don't derive from
// Copy/Clone, so cloning and updating isn't possible either.
//
// This is the most minimally invasive approach I could come up with.
if let Some(exceptions_cfg_path) = exceptions_cfg_path {
// TOML can't have unnamed arrays at the root.
#[derive(Deserialize)]
pub struct ExceptionsConfig {
pub exceptions: Vec<licenses::cfg::Exception>,
}

let content = std::fs::read_to_string(&exceptions_cfg_path)
.with_context(|| format!("failed to read config from {exceptions_cfg_path}"))?;

let ex_cfg: ExceptionsConfig = toml::from_str(&content).with_context(|| {
format!("failed to deserialize config from '{exceptions_cfg_path}'")
})?;

if cfg.licenses.is_some() {
let l = cfg.licenses.unwrap_or_default();

let exceptions = l
.exceptions
.into_iter()
.chain(ex_cfg.exceptions.into_iter())
.collect();

cfg.licenses = Some(licenses::Config { exceptions, ..l });
}
};

log::info!("using config from {cfg_path}");

let id = files.add(&cfg_path, cfg_contents);
Expand All @@ -225,10 +190,17 @@ impl ValidConfig {
.validate(id, files, &mut diags);

let bans = cfg.bans.unwrap_or_default().validate(id, files, &mut diags);
let licenses = cfg
let mut licenses = cfg
.licenses
.unwrap_or_default()
.validate(id, files, &mut diags);

// Allow for project-local exceptions. Relevant in corporate environments.
// https://github.com/EmbarkStudios/cargo-deny/issues/541
if let Some(ecp) = exceptions_cfg_path {
licenses::cfg::load_exceptions(&mut licenses, ecp, files, &mut diags);
};

let sources = cfg
.sources
.unwrap_or_default()
Expand Down
2 changes: 0 additions & 2 deletions src/cargo-deny/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,6 @@ impl KrateContext {
}
}

// Allow for project-local exceptions. Relevant in corporate environments.
// https://github.com/EmbarkStudios/cargo-deny/issues/541
pub fn get_local_exceptions_path(&self) -> Option<PathBuf> {
let mut p = self.manifest_path.parent();

Expand Down
7 changes: 6 additions & 1 deletion src/licenses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,9 +348,14 @@ pub fn check(
.zip(ctx.cfg.exceptions.into_iter())
.filter_map(|(hit, exc)| if !hit { Some(exc) } else { None })
{
// Don't print warnings for exception overrides
if exc.file_id != ctx.cfg.file_id {
continue;
}

pack.push(diags::UnmatchedLicenseException {
license_exc_cfg: CfgCoord {
file: ctx.cfg.file_id,
file: exc.file_id,
span: exc.name.span,
},
});
Expand Down
108 changes: 86 additions & 22 deletions src/licenses/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,30 @@ impl Default for Config {
}
}

fn parse_license(
ls: &Spanned<String>,
v: &mut Vec<Licensee>,
diags: &mut Vec<Diagnostic>,
cfg_file: FileId,
) {
match spdx::Licensee::parse(ls.as_ref()) {
Ok(licensee) => {
v.push(Licensee::new(licensee, ls.span.clone()));
}
Err(pe) => {
let offset = ls.span.start + 1;
let span = pe.span.start + offset..pe.span.end + offset;
diags.push(
Diagnostic::error()
.with_message("invalid licensee")
.with_labels(vec![
Label::primary(cfg_file, span).with_message(format!("{}", pe.reason))
]),
);
}
}
}

impl crate::cfg::UnvalidatedConfig for Config {
type ValidCfg = ValidConfig;

Expand Down Expand Up @@ -223,32 +247,14 @@ impl crate::cfg::UnvalidatedConfig for Config {
}
}

let mut parse_license = |ls: &Spanned<String>, v: &mut Vec<Licensee>| {
match spdx::Licensee::parse(ls.as_ref()) {
Ok(licensee) => {
v.push(Licensee::new(licensee, ls.span.clone()));
}
Err(pe) => {
let offset = ls.span.start + 1;
let span = pe.span.start + offset..pe.span.end + offset;
diags.push(
Diagnostic::error()
.with_message("invalid licensee")
.with_labels(vec![Label::primary(cfg_file, span)
.with_message(format!("{}", pe.reason))]),
);
}
}
};

let mut denied = Vec::with_capacity(self.deny.len());
for d in &self.deny {
parse_license(d, &mut denied);
parse_license(d, &mut denied, diags, cfg_file);
}

let mut allowed: Vec<Licensee> = Vec::with_capacity(self.allow.len());
for a in &self.allow {
parse_license(a, &mut allowed);
parse_license(a, &mut allowed, diags, cfg_file);
}

denied.par_sort();
Expand All @@ -259,13 +265,14 @@ impl crate::cfg::UnvalidatedConfig for Config {
let mut allowed = Vec::with_capacity(exc.allow.len());

for allow in &exc.allow {
parse_license(allow, &mut allowed);
parse_license(allow, &mut allowed, diags, cfg_file);
}

exceptions.push(ValidException {
name: exc.name,
version: exc.version,
allowed,
file_id: cfg_file,
});
}

Expand Down Expand Up @@ -299,7 +306,7 @@ impl crate::cfg::UnvalidatedConfig for Config {
Diagnostic::error()
.with_message("unable to parse license expression")
.with_labels(vec![Label::primary(cfg_file, expr_span)
.with_message(format!("{}", err.reason))]),
.with_message(err.reason.to_string())]),
);

continue;
Expand Down Expand Up @@ -336,6 +343,61 @@ impl crate::cfg::UnvalidatedConfig for Config {
}
}

pub fn load_exceptions(
cfg: &mut ValidConfig,
path: crate::PathBuf,
files: &mut crate::diag::Files,
diags: &mut Vec<Diagnostic>,
) {
// TOML can't have unnamed arrays at the root.
#[derive(Deserialize)]
pub struct ExceptionsConfig {
pub exceptions: Vec<Exception>,
}

let content = match std::fs::read_to_string(&path) {
Ok(c) => c,
Err(err) => {
diags.push(
Diagnostic::error()
.with_message("failed to read exceptions override")
.with_notes(vec![format!("path = '{path}'"), format!("error = {err:#}")]),
);
return;
}
};

let exc_cfg: ExceptionsConfig = match toml::from_str(&content) {
Ok(ec) => ec,
Err(err) => {
diags.push(
Diagnostic::error()
.with_message("failed to deserialize exceptions override")
.with_notes(vec![format!("path = '{path}'"), format!("error = {err:#}")]),
);
return;
}
};

let file_id = files.add(path, content);

cfg.exceptions.reserve(exc_cfg.exceptions.len());
for exc in exc_cfg.exceptions {
let mut allowed = Vec::with_capacity(exc.allow.len());

for allow in &exc.allow {
parse_license(allow, &mut allowed, diags, file_id);
}

cfg.exceptions.push(ValidException {
name: exc.name,
version: exc.version,
allowed,
file_id,
});
}
}

#[doc(hidden)]
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct ValidClarification {
Expand All @@ -352,6 +414,7 @@ pub struct ValidException {
pub name: crate::Spanned<String>,
pub version: Option<VersionReq>,
pub allowed: Vec<Licensee>,
pub file_id: FileId,
}

pub type Licensee = Spanned<spdx::Licensee>;
Expand Down Expand Up @@ -423,6 +486,7 @@ mod test {
name: "adler32".to_owned().fake(),
allowed: vec![spdx::Licensee::parse("Zlib").unwrap().fake()],
version: Some(semver::VersionReq::parse("0.1.1").unwrap()),
file_id: cd.id,
}]
);
let p: PathBuf = "LICENSE".into();
Expand Down

0 comments on commit 9867908

Please sign in to comment.