From dc0db358abe19481e475e10c32149b53370f1a1c Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 30 May 2024 05:57:31 +0200 Subject: Merging upstream version 1.72.1+dfsg1. Signed-off-by: Daniel Baumann --- vendor/ui_test/src/dependencies.rs | 183 +++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 vendor/ui_test/src/dependencies.rs (limited to 'vendor/ui_test/src/dependencies.rs') diff --git a/vendor/ui_test/src/dependencies.rs b/vendor/ui_test/src/dependencies.rs new file mode 100644 index 000000000..800a3a447 --- /dev/null +++ b/vendor/ui_test/src/dependencies.rs @@ -0,0 +1,183 @@ +use cargo_metadata::{camino::Utf8PathBuf, DependencyKind}; +use cargo_platform::Cfg; +use color_eyre::eyre::{bail, Result}; +use std::{ + collections::{HashMap, HashSet}, + path::PathBuf, + process::Command, + str::FromStr, +}; + +use crate::{Config, Mode, OutputConflictHandling}; + +#[derive(Default, Debug)] +pub struct Dependencies { + /// All paths that must be imported with `-L dependency=`. This is for + /// finding proc macros run on the host and dependencies for the target. + pub import_paths: Vec, + /// The name as chosen in the `Cargo.toml` and its corresponding rmeta file. + pub dependencies: Vec<(String, Vec)>, +} + +fn cfgs(config: &Config) -> Result> { + let mut cmd = config.cfgs.build(&config.out_dir); + cmd.arg("--target").arg(config.target.as_ref().unwrap()); + let output = cmd.output()?; + let stdout = String::from_utf8(output.stdout)?; + + if !output.status.success() { + let stderr = String::from_utf8(output.stderr)?; + bail!( + "failed to obtain `cfg` information from {cmd:?}:\nstderr:\n{stderr}\n\nstdout:{stdout}" + ); + } + let mut cfgs = vec![]; + + for line in stdout.lines() { + cfgs.push(Cfg::from_str(line)?); + } + + Ok(cfgs) +} + +/// Compiles dependencies and returns the crate names and corresponding rmeta files. +pub fn build_dependencies(config: &mut Config) -> Result { + let manifest_path = match &config.dependencies_crate_manifest_path { + Some(path) => path.to_owned(), + None => return Ok(Default::default()), + }; + let manifest_path = &manifest_path; + config.fill_host_and_target()?; + eprintln!(" Building test dependencies..."); + let mut build = config.dependency_builder.build(&config.out_dir); + build.arg(manifest_path); + + if let Some(target) = &config.target { + build.arg(format!("--target={target}")); + } + + // Reusable closure for setting up the environment both for artifact generation and `cargo_metadata` + let set_locking = |cmd: &mut Command| match (&config.output_conflict_handling, &config.mode) { + (_, Mode::Yolo) => {} + (OutputConflictHandling::Error(_), _) => { + cmd.arg("--locked"); + } + _ => {} + }; + + set_locking(&mut build); + build.arg("--message-format=json"); + + let output = build.output()?; + + if !output.status.success() { + let stdout = String::from_utf8(output.stdout)?; + let stderr = String::from_utf8(output.stderr)?; + bail!("failed to compile dependencies:\ncommand: {build:?}\nstderr:\n{stderr}\n\nstdout:{stdout}"); + } + + // Collect all artifacts generated + let artifact_output = output.stdout; + let artifact_output = String::from_utf8(artifact_output)?; + let mut import_paths: HashSet = HashSet::new(); + let mut artifacts: HashMap<_, _> = artifact_output + .lines() + .filter_map(|line| { + let message = serde_json::from_str::(line).ok()?; + if let cargo_metadata::Message::CompilerArtifact(artifact) = message { + for filename in &artifact.filenames { + import_paths.insert(filename.parent().unwrap().into()); + } + Some((artifact.package_id, artifact.filenames)) + } else { + None + } + }) + .collect(); + + // Check which crates are mentioned in the crate itself + let mut metadata = cargo_metadata::MetadataCommand::new().cargo_command(); + metadata.arg("--manifest-path").arg(manifest_path); + config.dependency_builder.apply_env(&mut metadata); + set_locking(&mut metadata); + let output = metadata.output()?; + + if !output.status.success() { + let stdout = String::from_utf8(output.stdout)?; + let stderr = String::from_utf8(output.stderr)?; + bail!("failed to run cargo-metadata:\nstderr:\n{stderr}\n\nstdout:{stdout}"); + } + + let output = output.stdout; + let output = String::from_utf8(output)?; + + let cfg = cfgs(config)?; + + for line in output.lines() { + if !line.starts_with('{') { + continue; + } + let metadata: cargo_metadata::Metadata = serde_json::from_str(line)?; + // Only take artifacts that are defined in the Cargo.toml + + // First, find the root artifact + let root = metadata + .packages + .iter() + .find(|package| { + package.manifest_path.as_std_path().canonicalize().unwrap() + == manifest_path.canonicalize().unwrap() + }) + .unwrap(); + + // Then go over all of its dependencies + let dependencies = root + .dependencies + .iter() + .filter(|dep| matches!(dep.kind, DependencyKind::Normal)) + // Only consider dependencies that are enabled on the current target + .filter(|dep| match &dep.target { + Some(platform) => platform.matches(config.target.as_ref().unwrap(), &cfg), + None => true, + }) + .map(|dep| { + let package = metadata + .packages + .iter() + .find(|&p| p.name == dep.name && dep.req.matches(&p.version)) + .expect("dependency does not exist"); + ( + package, + dep.rename.clone().unwrap_or_else(|| package.name.clone()), + ) + }) + // Also expose the root crate + .chain(std::iter::once((root, root.name.clone()))) + .filter_map(|(package, name)| { + // Get the id for the package matching the version requirement of the dep + let id = &package.id; + // Return the name chosen in `Cargo.toml` and the path to the corresponding artifact + match artifacts.remove(id) { + Some(artifacts) => Some((name.replace('-', "_"), artifacts)), + None => { + if name == root.name { + // If there are no artifacts, this is the root crate and it is being built as a binary/test + // instead of a library. We simply add no artifacts, meaning you can't depend on functions + // and types declared in the root crate. + None + } else { + panic!("no artifact found for `{name}`(`{id}`):`\n{artifact_output}") + } + } + } + }) + .collect(); + let import_paths = import_paths.into_iter().collect(); + return Ok(Dependencies { + dependencies, + import_paths, + }); + } + + bail!("no json found in cargo-metadata output") +} -- cgit v1.2.3