summaryrefslogtreecommitdiffstats
path: root/vendor/ui_test/src/dependencies.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
commitdc0db358abe19481e475e10c32149b53370f1a1c (patch)
treeab8ce99c4b255ce46f99ef402c27916055b899ee /vendor/ui_test/src/dependencies.rs
parentReleasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff)
downloadrustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz
rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/ui_test/src/dependencies.rs')
-rw-r--r--vendor/ui_test/src/dependencies.rs183
1 files changed, 183 insertions, 0 deletions
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<PathBuf>,
+ /// The name as chosen in the `Cargo.toml` and its corresponding rmeta file.
+ pub dependencies: Vec<(String, Vec<Utf8PathBuf>)>,
+}
+
+fn cfgs(config: &Config) -> Result<Vec<Cfg>> {
+ 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<Dependencies> {
+ 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<PathBuf> = HashSet::new();
+ let mut artifacts: HashMap<_, _> = artifact_output
+ .lines()
+ .filter_map(|line| {
+ let message = serde_json::from_str::<cargo_metadata::Message>(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")
+}