Compare commits

...

19 Commits

Author SHA1 Message Date
Sebastian Ziebell e4329da791
Merge 190682ea4e into eee4ea2f5a 2024-04-27 03:28:40 +02:00
bors eee4ea2f5a Auto merge of #13812 - Muscraft:dont-always-inherit-workspace-lints, r=epage
fix(cargo-lints): Don't always inherit workspace lints

When working on changes for #13805, I noticed that we always passed the contents of `[workspace.lints.cargo]` into the currently implemented lints,  even if `[lints]` was not specified or did not contain `workspace = true`. This PR makes it so we only pass in the workspace cargo lints if `[lints]` contains `workspace = true`.

You can verify this change by looking at the first commit, where I added a test showing the current behavior, and looking at the second commit and seeing the test output no longer shows a warning about specifying `im-a-teapot`.
2024-04-27 00:56:12 +00:00
bors c4e19cc890 Auto merge of #13811 - ehuss:remove-sleep-test, r=weihanglo
Update SleepTraker returns_in_order unit test

This updates the `returns_in_order` SleepTracker unit test so that it is not so sensitive to how fast the system is running. Previously it assumed that the function calls would take less than a millisecond to finish, but that is not a valid assumption for a slow-running system.

I have changed it to simplify the test, with the assumption that it takes less than 30 seconds for it to run, which should have a safety margin of a few orders of magnitude.
2024-04-26 23:30:40 +00:00
Eric Huss 06fb65e753 Update SleepTraker returns_in_order unit test 2024-04-26 16:02:09 -07:00
Scott Schafer cf197fc499
fix(cargo-lints): Don't always inherit workspace lints 2024-04-26 16:37:41 -06:00
Scott Schafer c3b104e11e
test(cargo-lints): Show workspace lints always inherited 2024-04-26 16:26:36 -06:00
Sebastian Ziebell 190682ea4e
Add test with custom build script 2024-04-06 16:31:25 +02:00
Sebastian Ziebell 96d1d3aea8
Guard sbom logic behind unstable feature 2024-04-05 13:16:23 +02:00
Sebastian Ziebell 27003f31a8
Add test to read JSON
Still needs to check output.
2024-04-05 13:16:23 +02:00
Sebastian Ziebell b16b37bcdb
Add build type to dependency 2024-04-05 13:16:23 +02:00
Sebastian Ziebell 284e1bb954
Add test to check project with bin & lib
* extract sbom config into helper function
2024-04-05 13:16:23 +02:00
Sebastian Ziebell fcf4db432c
Add test file to check sbom output 2024-04-05 13:16:23 +02:00
Sebastian Ziebell 44b81ee9d7
Extract logic to fetch sbom output files
This extracts the logic to get the list of SBOM output file paths into
its own function in `BuildRunner` for a given Unit.
2024-04-05 13:16:23 +02:00
Sebastian Ziebell 292eeee6fa
Output package dependencies
This is similar to what the `cargo metadata` command outputs.
2024-04-05 13:16:23 +02:00
Sebastian Ziebell 5f0102b097
Trying to fetch all dependencies
This ignores dependencies for custom build scripts. The output should be
similar to what `cargo tree` reports.
2024-04-05 13:16:23 +02:00
Sebastian Ziebell 58f67531a0
Output dependencies for unit deps. 2024-04-05 13:16:21 +02:00
Sebastian Ziebell ad63e75446
Output source & profile 2024-04-05 13:16:08 +02:00
Sebastian Ziebell 6620b6be9f
Add Sbom types to serialize data 2024-04-05 13:16:02 +02:00
Sebastian Ziebell d0e60ec835
Explore location to generate SBOM precursor files
Similar to the generation of `depinfo` files, a function is called to
generated SBOM precursor file named `output_sbom`. It takes the
`BuildRunner` & the current `Unit`. The `sbom` flag can be specified as
a cargo build option, but it's currently not configured correctly. To
test the generation the flag is set to `true`.

This passes in the cargo build config `sbom`.
2024-04-05 12:02:14 +02:00
13 changed files with 564 additions and 46 deletions

View File

@ -46,6 +46,8 @@ pub struct BuildConfig {
pub future_incompat_report: bool,
/// Which kinds of build timings to output (empty if none).
pub timing_outputs: Vec<TimingOutput>,
/// Output SBOM precursor files.
pub sbom: bool,
}
fn default_parallelism() -> CargoResult<u32> {
@ -102,6 +104,16 @@ impl BuildConfig {
anyhow::bail!("-Zbuild-std requires --target");
}
// If sbom flag is set, it requires the unstable feature
let sbom = match gctx.get_env_os("CARGO_BUILD_SBOM") {
Some(sbom) => sbom == "true",
None => cfg.sbom == Some(true),
};
if sbom && !gctx.cli_unstable().sbom {
anyhow::bail!("Cargo build config 'sbom' is unstable; pass `-Zsbom` to enable it");
}
Ok(BuildConfig {
requested_kinds,
jobs,
@ -117,6 +129,7 @@ impl BuildConfig {
export_dir: None,
future_incompat_report: false,
timing_outputs: Vec::new(),
sbom,
})
}

View File

@ -294,6 +294,10 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> {
}
super::output_depinfo(&mut self, unit)?;
if self.bcx.build_config.sbom {
super::output_sbom(&mut self, unit)?;
}
}
for (script_meta, output) in self.build_script_outputs.lock().unwrap().iter() {
@ -422,6 +426,21 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> {
self.files().metadata(unit)
}
/// Returns the list of SBOM output file paths for a given Unit.
///
/// Only call this function when `sbom` is active.
pub fn sbom_output_files(&self, unit: &Unit) -> CargoResult<Vec<PathBuf>> {
assert!(self.bcx.build_config.sbom);
let files = self
.outputs(unit)?
.iter()
.filter(|o| matches!(o.flavor, FileFlavor::Normal | FileFlavor::Linkable))
.filter_map(|output_file| output_file.hardlink.as_ref())
.map(|link_dst| link_dst.with_extension("cargo-sbom.json"))
.collect::<Vec<_>>();
Ok(files)
}
pub fn is_primary_package(&self, unit: &Unit) -> bool {
self.primary_packages.contains(&unit.pkg.package_id())
}

View File

@ -47,6 +47,7 @@ pub(crate) mod layout;
mod links;
mod lto;
mod output_depinfo;
mod output_sbom;
pub mod rustdoc;
pub mod standard_lib;
mod timings;
@ -84,6 +85,7 @@ use self::job_queue::{Job, JobQueue, JobState, Work};
pub(crate) use self::layout::Layout;
pub use self::lto::Lto;
use self::output_depinfo::output_depinfo;
use self::output_sbom::output_sbom;
use self::unit_graph::UnitDep;
use crate::core::compiler::future_incompat::FutureIncompatReport;
pub use crate::core::compiler::unit::{Unit, UnitInterner};
@ -672,6 +674,7 @@ where
/// completion of other units will be added later in runtime, such as flags
/// from build scripts.
fn prepare_rustc(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> CargoResult<ProcessBuilder> {
let gctx = build_runner.bcx.gctx;
let is_primary = build_runner.is_primary_package(unit);
let is_workspace = build_runner.bcx.ws.is_member(&unit.pkg);
@ -684,12 +687,23 @@ fn prepare_rustc(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> CargoResult
build_deps_args(&mut base, build_runner, unit)?;
add_cap_lints(build_runner.bcx, unit, &mut base);
base.args(build_runner.bcx.rustflags_args(unit));
if build_runner.bcx.gctx.cli_unstable().binary_dep_depinfo {
if gctx.cli_unstable().binary_dep_depinfo {
base.arg("-Z").arg("binary-dep-depinfo");
}
if is_primary {
base.env("CARGO_PRIMARY_PACKAGE", "1");
if gctx.cli_unstable().sbom && build_runner.bcx.build_config.sbom {
let file_list = build_runner
.sbom_output_files(unit)?
.iter()
.map(|file| file.display().to_string())
.collect::<Vec<String>>()
.join(",");
base.env("CARGO_SBOM_PATH", file_list);
}
}
if unit.target.is_test() || unit.target.is_bench() {

View File

@ -0,0 +1,241 @@
//! cargo-sbom precursor files for external tools to create SBOM files from.
//! See [`output_sbom`] for more.
use std::{
collections::BTreeSet,
io::{BufWriter, Write},
path::PathBuf,
};
use cargo_util::paths::{self};
use cargo_util_schemas::core::PackageIdSpec;
use itertools::Itertools;
use serde::Serialize;
use crate::{
core::{profiles::Profile, PackageId, Target, TargetKind},
util::Rustc,
CargoResult,
};
use super::{unit_graph::UnitDep, BuildRunner, CrateType, Unit};
#[derive(Serialize, Clone, Debug, Copy)]
#[serde(rename_all = "kebab-case")]
enum SbomBuildType {
/// A package dependency
Normal,
/// A build script dependency
Build,
}
/// Typed version of a SBOM format version number.
pub struct SbomFormatVersion<const V: u32>;
impl<const V: u32> Serialize for SbomFormatVersion<V> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_u32(V)
}
}
/// A package dependency
#[derive(Serialize, Clone, Debug)]
struct SbomDependency {
name: String,
package_id: PackageId,
version: String,
features: Vec<String>,
}
impl From<&UnitDep> for SbomDependency {
fn from(dep: &UnitDep) -> Self {
let package_id = dep.unit.pkg.package_id();
let name = package_id.name().to_string();
let version = package_id.version().to_string();
let features = dep
.unit
.features
.iter()
.map(|f| f.to_string())
.collect_vec();
Self {
name,
package_id,
version,
features,
}
}
}
#[derive(Serialize, Clone, Debug)]
struct SbomPackage {
package_id: PackageId,
package: String,
version: String,
features: Vec<String>,
build_type: SbomBuildType,
extern_crate_name: String,
dependencies: Vec<SbomDependency>,
}
impl SbomPackage {
pub fn new(
dep: &UnitDep,
dependencies: Vec<SbomDependency>,
build_type: SbomBuildType,
) -> Self {
let package_id = dep.unit.pkg.package_id();
let package = package_id.name().to_string();
let version = package_id.version().to_string();
let features = dep
.unit
.features
.iter()
.map(|f| f.to_string())
.collect_vec();
Self {
package_id,
package,
version,
features,
build_type,
extern_crate_name: dep.extern_crate_name.to_string(),
dependencies,
}
}
}
#[derive(Serialize)]
struct SbomTarget {
kind: TargetKind,
crate_type: Option<CrateType>,
name: String,
edition: String,
}
impl From<&Target> for SbomTarget {
fn from(target: &Target) -> Self {
SbomTarget {
kind: target.kind().clone(),
crate_type: target.kind().rustc_crate_types().first().cloned(),
name: target.name().to_string(),
edition: target.edition().to_string(),
}
}
}
#[derive(Serialize, Clone)]
struct SbomRustc {
version: String,
wrapper: Option<PathBuf>,
commit_hash: Option<String>,
host: String,
}
impl From<&Rustc> for SbomRustc {
fn from(rustc: &Rustc) -> Self {
Self {
version: rustc.version.to_string(),
wrapper: rustc.wrapper.clone(),
commit_hash: rustc.commit_hash.clone(),
host: rustc.host.to_string(),
}
}
}
#[derive(Serialize)]
struct Sbom {
format_version: SbomFormatVersion<1>,
package_id: PackageIdSpec,
name: String,
version: String,
source: String,
target: SbomTarget,
profile: Profile,
packages: Vec<SbomPackage>,
features: Vec<String>,
rustc: SbomRustc,
}
impl Sbom {
pub fn new(unit: &Unit, packages: Vec<SbomPackage>, rustc: SbomRustc) -> Self {
let package_id = unit.pkg.summary().package_id().to_spec();
let name = unit.pkg.name().to_string();
let version = unit.pkg.version().to_string();
let source = unit.pkg.package_id().source_id().to_string();
let target = (&unit.target).into();
let profile = unit.profile.clone();
let features = unit.features.iter().map(|f| f.to_string()).collect();
Self {
format_version: SbomFormatVersion,
package_id,
name,
version,
source,
target,
profile,
packages,
features,
rustc,
}
}
}
/// Saves a `<artifact>.cargo-sbom.json` file for the given [`Unit`].
///
pub fn output_sbom(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> CargoResult<()> {
let bcx = build_runner.bcx;
let rustc: SbomRustc = bcx.rustc().into();
let packages = fetch_packages(build_runner, unit);
for sbom_output_file in build_runner.sbom_output_files(unit)? {
let sbom = Sbom::new(unit, packages.clone(), rustc.clone());
let mut outfile = BufWriter::new(paths::create(sbom_output_file)?);
let output = serde_json::to_string_pretty(&sbom)?;
write!(outfile, "{}", output)?;
}
Ok(())
}
/// Fetch all dependencies, including transitive ones. A dependency can also appear multiple times
/// if it's included with different versions.
fn fetch_packages(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> Vec<SbomPackage> {
let unit_graph = &build_runner.bcx.unit_graph;
let root_deps = build_runner.unit_deps(unit);
let mut result: Vec<SbomPackage> = Vec::new();
let mut queue: BTreeSet<&UnitDep> = root_deps.iter().collect();
let mut visited: BTreeSet<&UnitDep> = BTreeSet::new();
while let Some(package) = queue.pop_first() {
if visited.contains(package) {
continue;
}
let build_type = if package.unit.mode.is_run_custom_build() {
SbomBuildType::Build
} else {
SbomBuildType::Normal
};
let mut dependencies: BTreeSet<&UnitDep> = unit_graph[&package.unit].iter().collect();
let sbom_dependencies = dependencies.iter().map(|dep| (*dep).into()).collect_vec();
result.push(SbomPackage::new(package, sbom_dependencies, build_type));
visited.insert(package);
queue.append(&mut dependencies);
}
result
}

View File

@ -775,6 +775,7 @@ unstable_cli_options!(
publish_timeout: bool = ("Enable the `publish.timeout` key in .cargo/config.toml file"),
rustdoc_map: bool = ("Allow passing external documentation mappings to rustdoc"),
rustdoc_scrape_examples: bool = ("Allows Rustdoc to scrape code examples from reverse-dependencies"),
sbom: bool = ("Enable the `sbom` option in build config in .cargo/config.toml file"),
script: bool = ("Enable support for single-file, `.rs` packages"),
separate_nightlies: bool,
skip_rustdoc_fingerprint: bool,
@ -1157,9 +1158,10 @@ impl CliUnstable {
"publish-timeout" => self.publish_timeout = parse_empty(k, v)?,
"rustdoc-map" => self.rustdoc_map = parse_empty(k, v)?,
"rustdoc-scrape-examples" => self.rustdoc_scrape_examples = parse_empty(k, v)?,
"sbom" => self.sbom = parse_empty(k, v)?,
"script" => self.script = parse_empty(k, v)?,
"separate-nightlies" => self.separate_nightlies = parse_empty(k, v)?,
"skip-rustdoc-fingerprint" => self.skip_rustdoc_fingerprint = parse_empty(k, v)?,
"script" => self.script = parse_empty(k, v)?,
"target-applies-to-host" => self.target_applies_to_host = parse_empty(k, v)?,
"unstable-options" => self.unstable_options = parse_empty(k, v)?,
_ => bail!("\

View File

@ -1147,11 +1147,26 @@ impl<'gctx> Workspace<'gctx> {
}
pub fn emit_warnings(&self) -> CargoResult<()> {
let ws_lints = self
.root_maybe()
.workspace_config()
.inheritable()
.and_then(|i| i.lints().ok())
.unwrap_or_default();
let ws_cargo_lints = ws_lints
.get("cargo")
.cloned()
.unwrap_or_default()
.into_iter()
.map(|(k, v)| (k.replace('-', "_"), v))
.collect();
for (path, maybe_pkg) in &self.packages.packages {
let path = path.join("Cargo.toml");
if let MaybePackage::Package(pkg) = maybe_pkg {
if self.gctx.cli_unstable().cargo_lints {
self.emit_lints(pkg, &path)?
self.emit_lints(pkg, &path, &ws_cargo_lints)?
}
}
let warnings = match maybe_pkg {
@ -1179,22 +1194,12 @@ impl<'gctx> Workspace<'gctx> {
Ok(())
}
pub fn emit_lints(&self, pkg: &Package, path: &Path) -> CargoResult<()> {
let ws_lints = self
.root_maybe()
.workspace_config()
.inheritable()
.and_then(|i| i.lints().ok())
.unwrap_or_default();
let ws_cargo_lints = ws_lints
.get("cargo")
.cloned()
.unwrap_or_default()
.into_iter()
.map(|(k, v)| (k.replace('-', "_"), v))
.collect();
pub fn emit_lints(
&self,
pkg: &Package,
path: &Path,
ws_cargo_lints: &manifest::TomlToolLints,
) -> CargoResult<()> {
let mut error_count = 0;
let toml_lints = pkg
.manifest()
@ -1212,11 +1217,21 @@ impl<'gctx> Workspace<'gctx> {
.map(|(name, lint)| (name.replace('-', "_"), lint))
.collect();
// We should only be using workspace lints if the `[lints]` table is
// present in the manifest, and `workspace` is set to `true`
let ws_cargo_lints = pkg
.manifest()
.resolved_toml()
.lints
.as_ref()
.is_some_and(|l| l.workspace)
.then(|| ws_cargo_lints);
check_im_a_teapot(
pkg,
&path,
&normalized_lints,
&ws_cargo_lints,
ws_cargo_lints,
&mut error_count,
self.gctx,
)?;
@ -1224,7 +1239,7 @@ impl<'gctx> Workspace<'gctx> {
pkg,
&path,
&normalized_lints,
&ws_cargo_lints,
ws_cargo_lints,
&mut error_count,
self.gctx,
)?;
@ -1232,7 +1247,7 @@ impl<'gctx> Workspace<'gctx> {
pkg,
&path,
&normalized_lints,
&ws_cargo_lints,
ws_cargo_lints,
&mut error_count,
self.gctx,
)?;

View File

@ -2578,6 +2578,8 @@ pub struct CargoBuildConfig {
pub rustc: Option<ConfigRelativePath>,
pub rustdoc: Option<ConfigRelativePath>,
pub out_dir: Option<ConfigRelativePath>,
/// Unstable feature `-Zsbom`.
pub sbom: Option<bool>,
}
/// Configuration for `build.target`.

View File

@ -88,7 +88,7 @@ impl Lint {
pub fn level(
&self,
pkg_lints: &TomlToolLints,
ws_lints: &TomlToolLints,
ws_lints: Option<&TomlToolLints>,
edition: Edition,
) -> (LintLevel, LintLevelReason) {
self.groups
@ -188,7 +188,7 @@ fn level_priority(
default_level: LintLevel,
edition_lint_opts: Option<(Edition, LintLevel)>,
pkg_lints: &TomlToolLints,
ws_lints: &TomlToolLints,
ws_lints: Option<&TomlToolLints>,
edition: Edition,
) -> (LintLevel, LintLevelReason, i8) {
let (unspecified_level, reason) = if let Some(level) = edition_lint_opts
@ -211,7 +211,7 @@ fn level_priority(
LintLevelReason::Package,
defined_level.priority(),
)
} else if let Some(defined_level) = ws_lints.get(name) {
} else if let Some(defined_level) = ws_lints.and_then(|l| l.get(name)) {
(
defined_level.level().into(),
LintLevelReason::Workspace,
@ -234,7 +234,7 @@ pub fn check_im_a_teapot(
pkg: &Package,
path: &Path,
pkg_lints: &TomlToolLints,
ws_lints: &TomlToolLints,
ws_lints: Option<&TomlToolLints>,
error_count: &mut usize,
gctx: &GlobalContext,
) -> CargoResult<()> {
@ -306,7 +306,7 @@ pub fn check_implicit_features(
pkg: &Package,
path: &Path,
pkg_lints: &TomlToolLints,
ws_lints: &TomlToolLints,
ws_lints: Option<&TomlToolLints>,
error_count: &mut usize,
gctx: &GlobalContext,
) -> CargoResult<()> {
@ -390,7 +390,7 @@ pub fn unused_dependencies(
pkg: &Package,
path: &Path,
pkg_lints: &TomlToolLints,
ws_lints: &TomlToolLints,
ws_lints: Option<&TomlToolLints>,
error_count: &mut usize,
gctx: &GlobalContext,
) -> CargoResult<()> {

View File

@ -90,13 +90,15 @@ impl<T> SleepTracker<T> {
#[test]
fn returns_in_order() {
let mut s = SleepTracker::new();
s.push(3, 3);
s.push(30_000, 30_000);
s.push(1, 1);
s.push(6, 6);
s.push(5, 5);
s.push(2, 2);
s.push(10000, 10000);
assert_eq!(s.len(), 6);
std::thread::sleep(Duration::from_millis(100));
assert_eq!(s.to_retry(), &[1, 2, 3, 5, 6]);
assert_eq!(s.len(), 2);
std::thread::sleep(Duration::from_millis(2));
assert_eq!(s.to_retry(), &[1]);
assert!(s.to_retry().is_empty());
let next = s.time_to_next().expect("should be next");
assert!(
next < Duration::from_millis(30_000),
"{next:?} should be less than 30s"
);
}

View File

@ -1,4 +1,4 @@
<svg width="1230px" height="722px" xmlns="http://www.w3.org/2000/svg">
<svg width="1230px" height="740px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
@ -79,23 +79,25 @@
</tspan>
<tspan x="10px" y="550px"><tspan> </tspan><tspan class="fg-cyan bold">-Z rustdoc-scrape-examples</tspan><tspan> Allows Rustdoc to scrape code examples from reverse-dependencies</tspan>
</tspan>
<tspan x="10px" y="568px"><tspan> </tspan><tspan class="fg-cyan bold">-Z script </tspan><tspan> Enable support for single-file, `.rs` packages</tspan>
<tspan x="10px" y="568px"><tspan> </tspan><tspan class="fg-cyan bold">-Z sbom </tspan><tspan> Enable the `sbom` option in build config in .cargo/config.toml file</tspan>
</tspan>
<tspan x="10px" y="586px"><tspan> </tspan><tspan class="fg-cyan bold">-Z target-applies-to-host </tspan><tspan> Enable the `target-applies-to-host` key in the .cargo/config.toml file</tspan>
<tspan x="10px" y="586px"><tspan> </tspan><tspan class="fg-cyan bold">-Z script </tspan><tspan> Enable support for single-file, `.rs` packages</tspan>
</tspan>
<tspan x="10px" y="604px"><tspan> </tspan><tspan class="fg-cyan bold">-Z trim-paths </tspan><tspan> Enable the `trim-paths` option in profiles</tspan>
<tspan x="10px" y="604px"><tspan> </tspan><tspan class="fg-cyan bold">-Z target-applies-to-host </tspan><tspan> Enable the `target-applies-to-host` key in the .cargo/config.toml file</tspan>
</tspan>
<tspan x="10px" y="622px"><tspan> </tspan><tspan class="fg-cyan bold">-Z unstable-options </tspan><tspan> Allow the usage of unstable options</tspan>
<tspan x="10px" y="622px"><tspan> </tspan><tspan class="fg-cyan bold">-Z trim-paths </tspan><tspan> Enable the `trim-paths` option in profiles</tspan>
</tspan>
<tspan x="10px" y="640px">
<tspan x="10px" y="640px"><tspan> </tspan><tspan class="fg-cyan bold">-Z unstable-options </tspan><tspan> Allow the usage of unstable options</tspan>
</tspan>
<tspan x="10px" y="658px"><tspan>Run with `</tspan><tspan class="fg-cyan bold">cargo -Z</tspan><tspan> </tspan><tspan class="fg-cyan">[FLAG] [COMMAND]</tspan><tspan>`</tspan>
<tspan x="10px" y="658px">
</tspan>
<tspan x="10px" y="676px">
<tspan x="10px" y="676px"><tspan>Run with `</tspan><tspan class="fg-cyan bold">cargo -Z</tspan><tspan> </tspan><tspan class="fg-cyan">[FLAG] [COMMAND]</tspan><tspan>`</tspan>
</tspan>
<tspan x="10px" y="694px"><tspan>See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html for more information about these flags.</tspan>
<tspan x="10px" y="694px">
</tspan>
<tspan x="10px" y="712px">
<tspan x="10px" y="712px"><tspan>See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html for more information about these flags.</tspan>
</tspan>
<tspan x="10px" y="730px">
</tspan>
</text>

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@ -982,3 +982,43 @@ error: `im_a_teapot` is specified
)
.run();
}
#[cargo_test]
fn dont_always_inherit_workspace_lints() {
let p = project()
.file(
"Cargo.toml",
r#"
[workspace]
members = ["foo"]
[workspace.lints.cargo]
im-a-teapot = "warn"
"#,
)
.file(
"foo/Cargo.toml",
r#"
cargo-features = ["test-dummy-unstable"]
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
im-a-teapot = true
"#,
)
.file("foo/src/lib.rs", "")
.build();
p.cargo("check -Zcargo-lints")
.masquerade_as_nightly_cargo(&["cargo-lints"])
.with_stderr(
"\
[CHECKING] foo v0.0.1 ([CWD]/foo)
[FINISHED] [..]
",
)
.run();
}

View File

@ -164,6 +164,7 @@ mod rustdoc_extern_html;
mod rustdocflags;
mod rustflags;
mod rustup;
mod sbom;
mod script;
mod search;
mod shell_quoting;

167
tests/testsuite/sbom.rs Normal file
View File

@ -0,0 +1,167 @@
//! Tests for cargo-sbom precursor files.
use std::{fs::File, io::BufReader, path::Path};
use cargo_test_support::{basic_bin_manifest, project, ProjectBuilder};
fn read_json<P: AsRef<Path>>(path: P) -> anyhow::Result<serde_json::Value> {
let file = File::open(path)?;
let reader = BufReader::new(file);
Ok(serde_json::from_reader(reader)?)
}
fn configured_project() -> ProjectBuilder {
project().file(
".cargo/config.toml",
r#"
[build]
sbom = true
"#,
)
}
#[cargo_test]
fn build_sbom_using_cargo_config() {
let p = project()
.file(
".cargo/config.toml",
r#"
[build]
sbom = true
"#,
)
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/main.rs", r#"fn main() {}"#)
.build();
p.cargo("build -Zsbom")
.masquerade_as_nightly_cargo(&["sbom"])
.run();
let file = p.bin("foo").with_extension("cargo-sbom.json");
assert!(file.is_file());
}
#[cargo_test]
fn build_sbom_using_env_var() {
let p = project()
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/foo.rs", r#"fn main() {}"#)
.build();
p.cargo("build -Zsbom")
.env("CARGO_BUILD_SBOM", "true")
.masquerade_as_nightly_cargo(&["sbom"])
.run();
let file = p.bin("foo").with_extension("cargo-sbom.json");
assert!(file.is_file());
}
#[cargo_test]
fn build_sbom_project_bin_and_lib() {
let p = configured_project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "1.2.3"
authors = []
[lib]
crate-type = ["rlib"]
"#,
)
.file("src/main.rs", r#"fn main() { let _i = foo::give_five(); }"#)
.file("src/lib.rs", r#"pub fn give_five() -> i32 { 5 }"#)
.build();
p.cargo("build -Zsbom")
.stream()
.masquerade_as_nightly_cargo(&["sbom"])
.run();
assert!(p.bin("foo").with_extension("cargo-sbom.json").is_file());
assert_eq!(
1,
p.glob(p.target_debug_dir().join("libfoo.cargo-sbom.json"))
.count()
);
}
#[cargo_test]
fn build_sbom_with_simple_build_script() {
let p = configured_project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
build = "build.rs"
"#,
)
.file("src/main.rs", "#[cfg(foo)] fn main() {}")
.file(
"build.rs",
r#"fn main() { println!("cargo::rustc-cfg=foo"); }"#,
)
.build();
p.cargo("build -Zsbom")
.stream()
.masquerade_as_nightly_cargo(&["sbom"])
.run();
let path = p.bin("foo").with_extension("cargo-sbom.json");
assert!(path.is_file());
let _json = read_json(path).expect("Failed to read JSON");
// TODO: check SBOM output
}
#[cargo_test]
fn build_sbom_with_build_dependencies() {
let p = configured_project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies]
bar = { path = "./bar" }
"#,
)
.file("src/main.rs", "fn main() { let _i = bar::bar(); }")
.file("bar/src/lib.rs", "pub fn bar() -> i32 { 2 }")
.file(
"bar/Cargo.toml",
r#"
[package]
name = "bar"
version = "0.1.0"
build = "build.rs"
[build-dependencies]
cc = "1.0.46"
"#,
)
.file(
"bar/build.rs",
r#"fn main() { println!("cargo::rustc-cfg=foo"); }"#,
)
.build();
p.cargo("build -Zsbom")
.stream()
.masquerade_as_nightly_cargo(&["sbom"])
.run();
let path = p.bin("foo").with_extension("cargo-sbom.json");
let _json = read_json(path).expect("Failed to read JSON");
// TODO: check SBOM output
}