Skip to content

Commit 4cebd13

Browse files
committed
Auto merge of #12289 - epage:basic, r=weihanglo
fix: Allow embedded manifests in all commands ### What does this PR try to resolve? This is a part of #12207. One of the goals is for embedded manifests to be a first class citizen. If you have a script, you should be able to run tests on it, for example. This expands the error check from just `Cargo.toml` to also single-file packages so you can use it in `--manifest-path`. This, however, does mean that these *can* be used in places that likely won't work yet, like `cargo publish`. ### How should we test and review this PR? By commit. We introduce tests for basic commands and then implement and refine the support for this. ### Additional information Other information you want to mention in this PR, such as prior arts, future extensions, an unresolved problem, or a TODO list.
2 parents 3de1cc4 + d8583f4 commit 4cebd13

File tree

4 files changed

+491
-27
lines changed

4 files changed

+491
-27
lines changed

src/bin/cargo/commands/run.rs

+2-9
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
8585
ops::run(&ws, &compile_opts, &values_os(args, "args")).map_err(|err| to_run_error(config, err))
8686
}
8787

88+
/// See also `util/toml/mod.rs`s `is_embedded`
8889
pub fn is_manifest_command(arg: &str) -> bool {
8990
let path = Path::new(arg);
9091
1 < path.components().count()
@@ -98,15 +99,7 @@ pub fn exec_manifest_command(config: &Config, cmd: &str, args: &[OsString]) -> C
9899
}
99100

100101
let manifest_path = Path::new(cmd);
101-
let manifest_path = config.cwd().join(manifest_path);
102-
let manifest_path = cargo_util::paths::normalize_path(&manifest_path);
103-
if !manifest_path.exists() {
104-
return Err(anyhow::format_err!(
105-
"manifest path `{}` does not exist",
106-
manifest_path.display()
107-
)
108-
.into());
109-
}
102+
let manifest_path = root_manifest(Some(manifest_path), config)?;
110103
let mut ws = Workspace::new(&manifest_path, config)?;
111104
if config.cli_unstable().avoid_dev_deps {
112105
ws.set_require_optional_deps(false);

src/cargo/util/command_prelude.rs

+29-16
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::CargoResult;
1515
use anyhow::bail;
1616
use cargo_util::paths;
1717
use std::ffi::{OsStr, OsString};
18+
use std::path::Path;
1819
use std::path::PathBuf;
1920

2021
pub use crate::core::compiler::CompileMode;
@@ -339,22 +340,7 @@ pub trait ArgMatchesExt {
339340
}
340341

341342
fn root_manifest(&self, config: &Config) -> CargoResult<PathBuf> {
342-
if let Some(path) = self.value_of_path("manifest-path", config) {
343-
// In general, we try to avoid normalizing paths in Cargo,
344-
// but in this particular case we need it to fix #3586.
345-
let path = paths::normalize_path(&path);
346-
if !path.ends_with("Cargo.toml") {
347-
anyhow::bail!("the manifest-path must be a path to a Cargo.toml file")
348-
}
349-
if !path.exists() {
350-
anyhow::bail!(
351-
"manifest path `{}` does not exist",
352-
self._value_of("manifest-path").unwrap()
353-
)
354-
}
355-
return Ok(path);
356-
}
357-
find_root_manifest_for_wd(config.cwd())
343+
root_manifest(self._value_of("manifest-path").map(Path::new), config)
358344
}
359345

360346
fn workspace<'a>(&self, config: &'a Config) -> CargoResult<Workspace<'a>> {
@@ -792,6 +778,33 @@ pub fn values_os(args: &ArgMatches, name: &str) -> Vec<OsString> {
792778
args._values_of_os(name)
793779
}
794780

781+
pub fn root_manifest(manifest_path: Option<&Path>, config: &Config) -> CargoResult<PathBuf> {
782+
if let Some(manifest_path) = manifest_path {
783+
let path = config.cwd().join(manifest_path);
784+
// In general, we try to avoid normalizing paths in Cargo,
785+
// but in this particular case we need it to fix #3586.
786+
let path = paths::normalize_path(&path);
787+
if !path.ends_with("Cargo.toml") && !crate::util::toml::is_embedded(&path) {
788+
anyhow::bail!("the manifest-path must be a path to a Cargo.toml file")
789+
}
790+
if !path.exists() {
791+
anyhow::bail!("manifest path `{}` does not exist", manifest_path.display())
792+
}
793+
if path.is_dir() {
794+
anyhow::bail!(
795+
"manifest path `{}` is a directory but expected a file",
796+
manifest_path.display()
797+
)
798+
}
799+
if crate::util::toml::is_embedded(&path) && !config.cli_unstable().script {
800+
anyhow::bail!("embedded manifest `{}` requires `-Zscript`", path.display())
801+
}
802+
Ok(path)
803+
} else {
804+
find_root_manifest_for_wd(config.cwd())
805+
}
806+
}
807+
795808
#[track_caller]
796809
pub fn ignore_unknown<T: Default>(r: Result<T, clap::parser::MatchesError>) -> T {
797810
match r {

src/cargo/util/toml/mod.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,12 @@ pub fn read_manifest(
7474
.map_err(|err| ManifestError::new(err, path.into()))
7575
}
7676

77-
fn is_embedded(path: &Path) -> bool {
77+
/// See also `bin/cargo/commands/run.rs`s `is_manifest_command`
78+
pub fn is_embedded(path: &Path) -> bool {
7879
let ext = path.extension();
79-
ext.is_none() || ext == Some(OsStr::new("rs"))
80+
ext == Some(OsStr::new("rs")) ||
81+
// Provide better errors by not considering directories to be embedded manifests
82+
(ext.is_none() && path.is_file())
8083
}
8184

8285
/// Parse an already-loaded `Cargo.toml` as a Cargo manifest.

0 commit comments

Comments
 (0)