Skip to content

Commit 5137905

Browse files
committed
Auto merge of #10335 - weihanglo:issue-10283, r=alexcrichton
Normalize --path when install bin outside current workspace
2 parents 0673982 + 76301eb commit 5137905

File tree

2 files changed

+84
-6
lines changed

2 files changed

+84
-6
lines changed

src/bin/cargo/commands/install.rs

+19-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
use crate::command_prelude::*;
22

3-
use cargo::core::{GitReference, SourceId};
3+
use cargo::core::{GitReference, SourceId, Workspace};
44
use cargo::ops;
55
use cargo::util::IntoUrl;
66

7+
use cargo_util::paths;
8+
79
pub fn cli() -> App {
810
subcommand("install")
911
.about("Install a Rust binary. Default location is $HOME/.cargo/bin")
@@ -80,13 +82,20 @@ pub fn cli() -> App {
8082
}
8183

8284
pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
83-
if let Some(path) = args.value_of_path("path", config) {
85+
let path = args.value_of_path("path", config);
86+
if let Some(path) = &path {
8487
config.reload_rooted_at(path)?;
8588
} else {
8689
// TODO: Consider calling set_search_stop_path(home).
8790
config.reload_rooted_at(config.home().clone().into_path_unlocked())?;
8891
}
8992

93+
// In general, we try to avoid normalizing paths in Cargo,
94+
// but in these particular cases we need it to fix rust-lang/cargo#10283.
95+
// (Handle `SourceId::for_path` and `Workspace::new`,
96+
// but not `Config::reload_rooted_at` which is always cwd)
97+
let path = path.map(|p| paths::normalize_path(&p));
98+
9099
let krates = args
91100
.values_of("crate")
92101
.unwrap_or_default()
@@ -106,7 +115,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
106115
GitReference::DefaultBranch
107116
};
108117
SourceId::for_git(&url, gitref)?
109-
} else if let Some(path) = args.value_of_path("path", config) {
118+
} else if let Some(path) = &path {
110119
SourceId::for_path(&path)?
111120
} else if krates.is_empty() {
112121
from_cwd = true;
@@ -125,9 +134,14 @@ pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
125134
// We only provide workspace information for local crate installation from
126135
// one of the following sources:
127136
// - From current working directory (only work for edition 2015).
128-
// - From a specific local file path.
129-
let workspace = if from_cwd || args.is_present("path") {
137+
// - From a specific local file path (from `--path` arg).
138+
//
139+
// This workspace information is for emitting helpful messages from
140+
// `ArgMatchesExt::compile_options` and won't affect the actual compilation.
141+
let workspace = if from_cwd {
130142
args.workspace(config).ok()
143+
} else if let Some(path) = &path {
144+
Workspace::new(&path.join("Cargo.toml"), config).ok()
131145
} else {
132146
None
133147
};

tests/testsuite/install.rs

+65-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use cargo_test_support::cross_compile;
77
use cargo_test_support::git;
88
use cargo_test_support::registry::{self, registry_path, registry_url, Package};
99
use cargo_test_support::{
10-
basic_manifest, cargo_process, no_such_file_err_msg, project, symlink_supported, t,
10+
basic_manifest, cargo_process, no_such_file_err_msg, project, project_in, symlink_supported, t,
1111
};
1212

1313
use cargo_test_support::install::{
@@ -493,6 +493,70 @@ but found cargo.toml please try to rename it to Cargo.toml. --path must point to
493493
.run();
494494
}
495495

496+
#[cargo_test]
497+
fn install_relative_path_outside_current_ws() {
498+
let p = project()
499+
.file(
500+
"Cargo.toml",
501+
r#"
502+
[package]
503+
name = "bar"
504+
version = "0.1.0"
505+
authors = []
506+
507+
[workspace]
508+
members = ["baz"]
509+
"#,
510+
)
511+
.file("src/main.rs", "fn main() {}")
512+
.file(
513+
"baz/Cargo.toml",
514+
r#"
515+
[package]
516+
name = "baz"
517+
version = "0.1.0"
518+
authors = []
519+
edition = "2021"
520+
521+
[dependencies]
522+
foo = "1"
523+
"#,
524+
)
525+
.file("baz/src/lib.rs", "")
526+
.build();
527+
528+
let _bin_project = project_in("bar")
529+
.file("src/main.rs", "fn main() {}")
530+
.build();
531+
532+
p.cargo("install --path ../bar/foo")
533+
.with_stderr(&format!(
534+
"\
535+
[INSTALLING] foo v0.0.1 ([..]/bar/foo)
536+
[COMPILING] foo v0.0.1 ([..]/bar/foo)
537+
[FINISHED] release [..]
538+
[INSTALLING] {home}/bin/foo[EXE]
539+
[INSTALLED] package `foo v0.0.1 ([..]/bar/foo)` (executable `foo[EXE]`)
540+
[WARNING] be sure to add [..]
541+
",
542+
home = cargo_home().display(),
543+
))
544+
.run();
545+
546+
// Validate the workspace error message to display available targets.
547+
p.cargo("install --path ../bar/foo --bin")
548+
.with_status(101)
549+
.with_stderr(
550+
"\
551+
[ERROR] \"--bin\" takes one argument.
552+
Available binaries:
553+
foo
554+
555+
",
556+
)
557+
.run();
558+
}
559+
496560
#[cargo_test]
497561
fn multiple_crates_error() {
498562
let p = git::repo(&paths::root().join("foo"))

0 commit comments

Comments
 (0)