WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit 585b8a9

Browse files
committed
fix(build-analysis): validate target source paths of root units
1 parent fba9183 commit 585b8a9

File tree

2 files changed

+171
-61
lines changed

2 files changed

+171
-61
lines changed

src/cargo/ops/cargo_compile/mod.rs

Lines changed: 121 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ use crate::util::log_message::LogMessage;
6060
use crate::util::{CargoResult, StableHasher};
6161

6262
mod compile_filter;
63-
use annotate_snippets::Level;
63+
use annotate_snippets::{Group, Level, Origin};
6464
pub use compile_filter::{CompileFilter, FilterRule, LibRule};
6565

6666
pub(super) mod unit_generator;
@@ -535,6 +535,27 @@ pub fn create_bcx<'a, 'gctx>(
535535
.extend(args);
536536
}
537537

538+
// Validate target src path for each root unit
539+
let mut error_count: usize = 0;
540+
for unit in &units {
541+
if let Some(target_src_path) = unit.target.src_path().path() {
542+
validate_target_path_as_source_file(
543+
gctx,
544+
target_src_path,
545+
unit.target.name(),
546+
unit.target.kind(),
547+
unit.pkg.manifest_path(),
548+
&mut error_count,
549+
)?
550+
}
551+
}
552+
if error_count > 0 {
553+
let plural: &str = if error_count > 1 { "s" } else { "" };
554+
anyhow::bail!(
555+
"could not compile due to {error_count} previous target resolution error{plural}"
556+
);
557+
}
558+
538559
if honor_rust_version.unwrap_or(true) {
539560
let rustc_version = target_data.rustc.version.clone().into();
540561

@@ -602,6 +623,105 @@ where `<compatible-ver>` is the latest version supporting rustc {rustc_version}"
602623
Ok(bcx)
603624
}
604625

626+
// Checks if a target path exists and is a source file, not a directory
627+
fn validate_target_path_as_source_file(
628+
gctx: &GlobalContext,
629+
target_path: &std::path::Path,
630+
target_name: &str,
631+
target_kind: &TargetKind,
632+
unit_manifest_path: &std::path::Path,
633+
error_count: &mut usize,
634+
) -> CargoResult<()> {
635+
if !target_path.exists() {
636+
*error_count += 1;
637+
638+
let err_msg = format!(
639+
"can't find {} `{}` at path `{}`",
640+
target_kind.description(),
641+
target_name,
642+
target_path.display()
643+
);
644+
645+
let group = Group::with_title(Level::ERROR.primary_title(err_msg)).element(Origin::path(
646+
unit_manifest_path.to_str().unwrap_or_default(),
647+
));
648+
649+
gctx.shell().print_report(&[group], true)?;
650+
} else if target_path.is_dir() {
651+
*error_count += 1;
652+
653+
// suggest setting the path to a likely entrypoint
654+
let main_rs = target_path.join("main.rs");
655+
let lib_rs = target_path.join("lib.rs");
656+
657+
let suggested_files_opt = match target_kind {
658+
TargetKind::Lib(_) => {
659+
if lib_rs.exists() {
660+
Some(format!("`{}`", lib_rs.display()))
661+
} else {
662+
None
663+
}
664+
}
665+
TargetKind::Bin => {
666+
if main_rs.exists() {
667+
Some(format!("`{}`", main_rs.display()))
668+
} else {
669+
None
670+
}
671+
}
672+
TargetKind::Test => {
673+
if main_rs.exists() {
674+
Some(format!("`{}`", main_rs.display()))
675+
} else {
676+
None
677+
}
678+
}
679+
TargetKind::ExampleBin => {
680+
if main_rs.exists() {
681+
Some(format!("`{}`", main_rs.display()))
682+
} else {
683+
None
684+
}
685+
}
686+
TargetKind::Bench => {
687+
if main_rs.exists() {
688+
Some(format!("`{}`", main_rs.display()))
689+
} else {
690+
None
691+
}
692+
}
693+
TargetKind::ExampleLib(_) => {
694+
if lib_rs.exists() {
695+
Some(format!("`{}`", lib_rs.display()))
696+
} else {
697+
None
698+
}
699+
}
700+
_ => None,
701+
};
702+
703+
let err_msg = format!(
704+
"path `{}` for {} `{}` is a directory, but a source file was expected.",
705+
target_path.display(),
706+
target_kind.description(),
707+
target_name,
708+
);
709+
let mut group = Group::with_title(Level::ERROR.primary_title(err_msg)).element(
710+
Origin::path(unit_manifest_path.to_str().unwrap_or_default()),
711+
);
712+
713+
if let Some(suggested_files) = suggested_files_opt {
714+
group = group.element(
715+
Level::HELP.message(format!("an entry point exists at {}", suggested_files)),
716+
);
717+
}
718+
719+
gctx.shell().print_report(&[group], true)?;
720+
}
721+
722+
Ok(())
723+
}
724+
605725
/// This is used to rebuild the unit graph, sharing host dependencies if possible,
606726
/// and applying other unit adjustments based on the whole graph.
607727
///

tests/testsuite/bad_config.rs

Lines changed: 50 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -3776,10 +3776,9 @@ fn nonexistent_example_target_path() {
37763776
p.cargo("check --examples")
37773777
.with_status(101)
37783778
.with_stderr_data(str![[r#"
3779-
[CHECKING] foo v1.0.0 ([ROOT]/foo)
3780-
[ERROR] couldn't read `examples/null.rs`: [NOT_FOUND]
3781-
3782-
[ERROR] could not compile `foo` (example "bar") due to 1 previous error
3779+
[ERROR] can't find example `bar` at path `[ROOT]/foo/examples/null.rs`
3780+
--> [ROOT]/foo/Cargo.toml
3781+
[ERROR] could not compile due to 1 previous target resolution error
37833782
37843783
"#]])
37853784
.run();
@@ -3805,10 +3804,9 @@ fn nonexistent_library_target_path() {
38053804
p.cargo("check")
38063805
.with_status(101)
38073806
.with_stderr_data(str![[r#"
3808-
[CHECKING] foo v1.0.0 ([ROOT]/foo)
3809-
[ERROR] couldn't read `src/null.rs`: [NOT_FOUND]
3810-
3811-
[ERROR] could not compile `foo` (lib) due to 1 previous error
3807+
[ERROR] can't find lib `foo` at path `[ROOT]/foo/src/null.rs`
3808+
--> [ROOT]/foo/Cargo.toml
3809+
[ERROR] could not compile due to 1 previous target resolution error
38123810
38133811
"#]])
38143812
.run();
@@ -3834,10 +3832,9 @@ fn nonexistent_binary_target_path() {
38343832
p.cargo("check")
38353833
.with_status(101)
38363834
.with_stderr_data(str![[r#"
3837-
[CHECKING] foo v1.0.0 ([ROOT]/foo)
3838-
[ERROR] couldn't read `src/null.rs`: [NOT_FOUND]
3839-
3840-
[ERROR] could not compile `foo` (bin "null") due to 1 previous error
3835+
[ERROR] can't find bin `null` at path `[ROOT]/foo/src/null.rs`
3836+
--> [ROOT]/foo/Cargo.toml
3837+
[ERROR] could not compile due to 1 previous target resolution error
38413838
38423839
"#]])
38433840
.run();
@@ -3863,10 +3860,9 @@ fn nonexistent_test_target_path() {
38633860
p.cargo("test")
38643861
.with_status(101)
38653862
.with_stderr_data(str![[r#"
3866-
[COMPILING] foo v1.0.0 ([ROOT]/foo)
3867-
[ERROR] couldn't read `src/null.rs`: [NOT_FOUND]
3868-
3869-
[ERROR] could not compile `foo` (test "null") due to 1 previous error
3863+
[ERROR] can't find integration-test `null` at path `[ROOT]/foo/src/null.rs`
3864+
--> [ROOT]/foo/Cargo.toml
3865+
[ERROR] could not compile due to 1 previous target resolution error
38703866
38713867
"#]])
38723868
.run();
@@ -3892,10 +3888,9 @@ fn nonexistent_bench_target_path() {
38923888
p.cargo("bench")
38933889
.with_status(101)
38943890
.with_stderr_data(str![[r#"
3895-
[COMPILING] foo v1.0.0 ([ROOT]/foo)
3896-
[ERROR] couldn't read `src/null.rs`: [NOT_FOUND]
3897-
3898-
[ERROR] could not compile `foo` (bench "null") due to 1 previous error
3891+
[ERROR] can't find bench `null` at path `[ROOT]/foo/src/null.rs`
3892+
--> [ROOT]/foo/Cargo.toml
3893+
[ERROR] could not compile due to 1 previous target resolution error
38993894
39003895
"#]])
39013896
.run();
@@ -3922,10 +3917,9 @@ fn directory_as_example_target_path() {
39223917
p.cargo("check --example bar")
39233918
.with_status(101)
39243919
.with_stderr_data(str![[r#"
3925-
[CHECKING] foo v1.0.0 ([ROOT]/foo)
3926-
[ERROR] couldn't read `examples/bar`: Is a directory (os error 21)
3927-
3928-
[ERROR] could not compile `foo` (example "bar") due to 1 previous error
3920+
[ERROR] path `[ROOT]/foo/examples/bar` for example `bar` is a directory, but a source file was expected.
3921+
--> [ROOT]/foo/Cargo.toml
3922+
[ERROR] could not compile due to 1 previous target resolution error
39293923
39303924
"#]])
39313925
.run();
@@ -3951,10 +3945,9 @@ fn directory_as_library_target_path() {
39513945
p.cargo("check")
39523946
.with_status(101)
39533947
.with_stderr_data(str![[r#"
3954-
[CHECKING] foo v1.0.0 ([ROOT]/foo)
3955-
[ERROR] couldn't read `src/null`: Is a directory (os error 21)
3956-
3957-
[ERROR] could not compile `foo` (lib) due to 1 previous error
3948+
[ERROR] path `[ROOT]/foo/src/null` for lib `foo` is a directory, but a source file was expected.
3949+
--> [ROOT]/foo/Cargo.toml
3950+
[ERROR] could not compile due to 1 previous target resolution error
39583951
39593952
"#]])
39603953
.run();
@@ -3981,10 +3974,9 @@ fn directory_as_binary_target_path() {
39813974
p.cargo("check")
39823975
.with_status(101)
39833976
.with_stderr_data(str![[r#"
3984-
[CHECKING] foo v1.0.0 ([ROOT]/foo)
3985-
[ERROR] couldn't read `src/null`: Is a directory (os error 21)
3986-
3987-
[ERROR] could not compile `foo` (bin "null") due to 1 previous error
3977+
[ERROR] path `[ROOT]/foo/src/null` for bin `null` is a directory, but a source file was expected.
3978+
--> [ROOT]/foo/Cargo.toml
3979+
[ERROR] could not compile due to 1 previous target resolution error
39883980
39893981
"#]])
39903982
.run();
@@ -4011,10 +4003,9 @@ fn directory_as_test_target_path() {
40114003
p.cargo("test")
40124004
.with_status(101)
40134005
.with_stderr_data(str![[r#"
4014-
[COMPILING] foo v1.0.0 ([ROOT]/foo)
4015-
[ERROR] couldn't read `src/null`: Is a directory (os error 21)
4016-
4017-
[ERROR] could not compile `foo` (test "null") due to 1 previous error
4006+
[ERROR] path `[ROOT]/foo/src/null` for integration-test `null` is a directory, but a source file was expected.
4007+
--> [ROOT]/foo/Cargo.toml
4008+
[ERROR] could not compile due to 1 previous target resolution error
40184009
40194010
"#]])
40204011
.run();
@@ -4041,10 +4032,9 @@ fn directory_as_bench_target_path() {
40414032
p.cargo("bench")
40424033
.with_status(101)
40434034
.with_stderr_data(str![[r#"
4044-
[COMPILING] foo v1.0.0 ([ROOT]/foo)
4045-
[ERROR] couldn't read `src/null`: Is a directory (os error 21)
4046-
4047-
[ERROR] could not compile `foo` (bench "null") due to 1 previous error
4035+
[ERROR] path `[ROOT]/foo/src/null` for bench `null` is a directory, but a source file was expected.
4036+
--> [ROOT]/foo/Cargo.toml
4037+
[ERROR] could not compile due to 1 previous target resolution error
40484038
40494039
"#]])
40504040
.run();
@@ -4071,10 +4061,10 @@ fn directory_as_example_target_path_with_entrypoint() {
40714061
p.cargo("check --example bar")
40724062
.with_status(101)
40734063
.with_stderr_data(str![[r#"
4074-
[CHECKING] foo v1.0.0 ([ROOT]/foo)
4075-
[ERROR] couldn't read `examples/bar`: Is a directory (os error 21)
4076-
4077-
[ERROR] could not compile `foo` (example "bar") due to 1 previous error
4064+
[ERROR] path `[ROOT]/foo/examples/bar` for example `bar` is a directory, but a source file was expected.
4065+
--> [ROOT]/foo/Cargo.toml
4066+
= [HELP] an entry point exists at `[ROOT]/foo/examples/bar/main.rs`
4067+
[ERROR] could not compile due to 1 previous target resolution error
40784068
40794069
"#]])
40804070
.run();
@@ -4100,10 +4090,10 @@ fn directory_as_library_target_path_with_entrypoint() {
41004090
p.cargo("check")
41014091
.with_status(101)
41024092
.with_stderr_data(str![[r#"
4103-
[CHECKING] foo v1.0.0 ([ROOT]/foo)
4104-
[ERROR] couldn't read `src/null`: Is a directory (os error 21)
4105-
4106-
[ERROR] could not compile `foo` (lib) due to 1 previous error
4093+
[ERROR] path `[ROOT]/foo/src/null` for lib `foo` is a directory, but a source file was expected.
4094+
--> [ROOT]/foo/Cargo.toml
4095+
= [HELP] an entry point exists at `[ROOT]/foo/src/null/lib.rs`
4096+
[ERROR] could not compile due to 1 previous target resolution error
41074097
41084098
"#]])
41094099
.run();
@@ -4130,10 +4120,10 @@ fn directory_as_binary_target_path_with_entrypoint() {
41304120
p.cargo("check")
41314121
.with_status(101)
41324122
.with_stderr_data(str![[r#"
4133-
[CHECKING] foo v1.0.0 ([ROOT]/foo)
4134-
[ERROR] couldn't read `src/null`: Is a directory (os error 21)
4135-
4136-
[ERROR] could not compile `foo` (bin "null") due to 1 previous error
4123+
[ERROR] path `[ROOT]/foo/src/null` for bin `null` is a directory, but a source file was expected.
4124+
--> [ROOT]/foo/Cargo.toml
4125+
= [HELP] an entry point exists at `[ROOT]/foo/src/null/main.rs`
4126+
[ERROR] could not compile due to 1 previous target resolution error
41374127
41384128
"#]])
41394129
.run();
@@ -4160,10 +4150,10 @@ fn directory_as_test_target_path_with_entrypoint() {
41604150
p.cargo("test")
41614151
.with_status(101)
41624152
.with_stderr_data(str![[r#"
4163-
[COMPILING] foo v1.0.0 ([ROOT]/foo)
4164-
[ERROR] couldn't read `src/null`: Is a directory (os error 21)
4165-
4166-
[ERROR] could not compile `foo` (test "null") due to 1 previous error
4153+
[ERROR] path `[ROOT]/foo/src/null` for integration-test `null` is a directory, but a source file was expected.
4154+
--> [ROOT]/foo/Cargo.toml
4155+
= [HELP] an entry point exists at `[ROOT]/foo/src/null/main.rs`
4156+
[ERROR] could not compile due to 1 previous target resolution error
41674157
41684158
"#]])
41694159
.run();
@@ -4190,10 +4180,10 @@ fn directory_as_bench_target_path_with_entrypoint() {
41904180
p.cargo("bench")
41914181
.with_status(101)
41924182
.with_stderr_data(str![[r#"
4193-
[COMPILING] foo v1.0.0 ([ROOT]/foo)
4194-
[ERROR] couldn't read `src/null`: Is a directory (os error 21)
4195-
4196-
[ERROR] could not compile `foo` (bench "null") due to 1 previous error
4183+
[ERROR] path `[ROOT]/foo/src/null` for bench `null` is a directory, but a source file was expected.
4184+
--> [ROOT]/foo/Cargo.toml
4185+
= [HELP] an entry point exists at `[ROOT]/foo/src/null/main.rs`
4186+
[ERROR] could not compile due to 1 previous target resolution error
41974187
41984188
"#]])
41994189
.run();

0 commit comments

Comments
 (0)