mirror of https://github.com/rust-lang/cargo
Compare commits
19 Commits
904c3f87bb
...
e4329da791
Author | SHA1 | Date |
---|---|---|
Sebastian Ziebell | e4329da791 | |
bors | eee4ea2f5a | |
bors | c4e19cc890 | |
Eric Huss | 06fb65e753 | |
Scott Schafer | cf197fc499 | |
Scott Schafer | c3b104e11e | |
Sebastian Ziebell | 190682ea4e | |
Sebastian Ziebell | 96d1d3aea8 | |
Sebastian Ziebell | 27003f31a8 | |
Sebastian Ziebell | b16b37bcdb | |
Sebastian Ziebell | 284e1bb954 | |
Sebastian Ziebell | fcf4db432c | |
Sebastian Ziebell | 44b81ee9d7 | |
Sebastian Ziebell | 292eeee6fa | |
Sebastian Ziebell | 5f0102b097 | |
Sebastian Ziebell | 58f67531a0 | |
Sebastian Ziebell | ad63e75446 | |
Sebastian Ziebell | 6620b6be9f | |
Sebastian Ziebell | d0e60ec835 |
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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!("\
|
||||
|
|
|
@ -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,
|
||||
)?;
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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<()> {
|
||||
|
|
|
@ -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"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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 |
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -164,6 +164,7 @@ mod rustdoc_extern_html;
|
|||
mod rustdocflags;
|
||||
mod rustflags;
|
||||
mod rustup;
|
||||
mod sbom;
|
||||
mod script;
|
||||
mod search;
|
||||
mod shell_quoting;
|
||||
|
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue