Skip to content

Commit a929d53

Browse files
committed
Canonicalize built library paths before resolving duplicates
1 parent 9df9cd9 commit a929d53

2 files changed

Lines changed: 102 additions & 2 deletions

File tree

  • cargo-dylint/tests/integration
  • dylint/src/library_packages

‎cargo-dylint/tests/integration/list.rs‎

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use assert_cmd::cargo::cargo_bin_cmd;
77
use dylint_internal::{
88
CommandExt,
99
clippy_utils::{set_clippy_utils_dependency_revision, set_toolchain_channel},
10-
env,
10+
env, library_filename_with_toolchain,
1111
link::{debug_path_with_active_toolchain, debug_path_with_toolchain},
1212
msrv,
1313
rustup::{SanitizeEnvironment, active_toolchain},
@@ -16,10 +16,60 @@ use dylint_internal::{
1616
use predicates::prelude::*;
1717
use std::{
1818
env::join_paths,
19+
fmt::Write as _,
20+
fs::OpenOptions,
21+
io::Write,
1922
path::{Path, PathBuf},
2023
};
2124
use tempfile::tempdir;
2225

26+
#[test]
27+
fn metadata_and_lib_path_are_deduplicated() {
28+
let library_dir = tempdir().unwrap();
29+
let manifest_dir = tempdir().unwrap();
30+
#[cfg(unix)]
31+
let target_dir = tempdir().unwrap();
32+
33+
new_template(library_dir.path()).unwrap();
34+
let toolchain = active_toolchain(library_dir.path()).unwrap();
35+
36+
dylint_internal::cargo::init("package `metadata_and_lib_path_test`")
37+
.build()
38+
.current_dir(&manifest_dir)
39+
.args(["--name", "metadata_and_lib_path_test"])
40+
.success()
41+
.unwrap();
42+
43+
let library_dir_path = dunce::canonicalize(&library_dir).unwrap();
44+
append_workspace_metadata(manifest_dir.path(), [library_dir_path.as_path()]).unwrap();
45+
46+
// On Unix, the symlink makes canonicalization change the library path. Windows symlinks or
47+
// junctions can cause the same mismatch. This test does not create an alias on Windows,
48+
// where symlink creation can require additional privileges. The Windows case checks
49+
// deduplication without exercising alias resolution.
50+
#[cfg(unix)]
51+
std::os::unix::fs::symlink(&target_dir, manifest_dir.path().join("target")).unwrap();
52+
53+
cargo_bin_cmd!("cargo-dylint")
54+
.current_dir(&manifest_dir)
55+
.args(["dylint", "list", "--all"])
56+
.assert()
57+
.success();
58+
59+
let library_path = target_libraries_directory(manifest_dir.path(), &toolchain)
60+
.unwrap()
61+
.join(library_filename_with_toolchain("fill_me_in", &toolchain));
62+
63+
cargo_bin_cmd!("cargo-dylint")
64+
.current_dir(&manifest_dir)
65+
.args(["dylint", "list", "--all", "--no-build", "--lib-path"])
66+
.arg(&library_path)
67+
.assert()
68+
.success()
69+
// One occurrence in the library heading and one in its lint listing.
70+
.stdout(predicate::str::contains("fill_me_in").count(2));
71+
}
72+
2373
#[test]
2474
fn one_name_multiple_toolchains() {
2575
let tempdir = tempdir().unwrap();
@@ -227,6 +277,40 @@ fn relative_path() {
227277
}
228278
}
229279

280+
fn append_workspace_metadata<'a>(
281+
manifest_dir: &Path,
282+
lib_dirs: impl IntoIterator<Item = &'a Path>,
283+
) -> Result<()> {
284+
let manifest = manifest_dir.join("Cargo.toml");
285+
let mut file = OpenOptions::new()
286+
.append(true)
287+
.open(&manifest)
288+
.with_context(|| format!("Could not open `{}`", manifest.to_string_lossy()))?;
289+
290+
writeln!(file, "{}", workspace_metadata(lib_dirs))
291+
.with_context(|| format!("Could not write to `{}`", manifest.to_string_lossy()))?;
292+
293+
Ok(())
294+
}
295+
296+
fn workspace_metadata<'a>(lib_dirs: impl IntoIterator<Item = &'a Path>) -> String {
297+
let mut metadata = String::from(
298+
r"
299+
[workspace.metadata.dylint]
300+
libraries = [
301+
",
302+
);
303+
for lib_dir in lib_dirs {
304+
let path = toml::Value::String(lib_dir.to_string_lossy().into_owned());
305+
writeln!(&mut metadata, " {{ path = {path} }},").unwrap();
306+
}
307+
metadata.push_str(
308+
r"]
309+
",
310+
);
311+
metadata
312+
}
313+
230314
// smoelius: This test checks that if a library path is passed to `--path`, a "No library packages
231315
// found in ..." message is emitted.
232316
#[test]
@@ -260,3 +344,18 @@ fn target_debug(dir: &Path) -> Result<PathBuf> {
260344
let debug_dir = metadata.target_directory.join("debug");
261345
dunce::canonicalize(&debug_dir).with_context(|| format!("Could not canonicalize `{debug_dir}`"))
262346
}
347+
348+
// smoelius: Hack. This function duplicates logic from, e.g.,
349+
// `dylint::library_packages::Package::library_path_with_toolchain`.
350+
fn target_libraries_directory(dir: &Path, toolchain: &str) -> Result<PathBuf> {
351+
let target_directory = target_directory(dir)?;
352+
Ok(target_directory
353+
.join("dylint/libraries")
354+
.join(toolchain)
355+
.join("release"))
356+
}
357+
358+
fn target_directory(dir: &Path) -> Result<PathBuf> {
359+
let metadata = dylint_internal::cargo::metadata(dir)?;
360+
Ok(metadata.target_directory.into_std_path_buf())
361+
}

‎dylint/src/library_packages/mod.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,8 @@ pub fn build_library(opts: &opts::Dylint, package: &Package) -> Result<PathBuf>
532532
);
533533
}
534534

535-
Ok(path)
535+
dunce::canonicalize(&path)
536+
.with_context(|| format!("Could not canonicalize `{}`", path.display()))
536537
}
537538

538539
// smoelius: `pkg_dir` and `target_short_hash` are based on functions with the same names in

0 commit comments

Comments
 (0)