Merge branch 'master' of github.com:rust-lang/cargo into unknown-feature-resolver-1

This commit is contained in:
Alik Aslanyan 2021-05-20 08:34:48 +04:00
commit 766c3bbcb8
58 changed files with 875 additions and 269 deletions

View File

@ -54,6 +54,10 @@ jobs:
other: i686-pc-windows-gnu
steps:
- uses: actions/checkout@v2
- name: Update Rustup (temporary workaround)
run: rustup self update
shell: bash
if: startsWith(matrix.os, 'windows')
- run: rustup update --no-self-update ${{ matrix.rust }} && rustup default ${{ matrix.rust }}
- run: rustup target add ${{ matrix.other }}
- run: rustup component add rustc-dev llvm-tools-preview rust-docs

View File

@ -1,17 +1,47 @@
# Changelog
## Cargo 1.54 (2021-07-29)
[4369396c...HEAD](https://github.com/rust-lang/cargo/compare/4369396c...HEAD)
### Added
- Fetching from a git repository (such as the crates.io index) now displays
the network transfer rate.
[#9395](https://github.com/rust-lang/cargo/pull/9395)
### Changed
### Fixed
- Fixed `package.exclude` in `Cargo.toml` using inverted exclusions
(`!somefile`) when not in a git repository or when vendoring a dependency.
[#9186](https://github.com/rust-lang/cargo/pull/9186)
- Dep-info files now adjust build script `rerun-if-changed` paths to be
absolute paths.
[#9421](https://github.com/rust-lang/cargo/pull/9421)
### Nightly only
- Added `report` subcommand, and changed `cargo
describe-future-incompatibilitie` to `cargo report
future-incompatibilities`.
[#9438](https://github.com/rust-lang/cargo/pull/9438)
## Cargo 1.53 (2021-06-17)
[90691f2b...HEAD](https://github.com/rust-lang/cargo/compare/90691f2b...HEAD)
[90691f2b...rust-1.53.0](https://github.com/rust-lang/cargo/compare/90691f2b...rust-1.53.0)
### Added
### Changed
- 🔥 Cargo now supports git repositories where the default `HEAD` branch is not
"master". This also includes a switch to the version 3 `Cargo.lock` format
which can handle default branches correctly.
[#9133](https://github.com/rust-lang/cargo/pull/9133)
- 🔥 macOS targets now default to `unpacked` debuginfo.
[#9397](https://github.com/rust-lang/cargo/pull/9397)
[#9384](https://github.com/rust-lang/cargo/pull/9384)
[#9392](https://github.com/rust-lang/cargo/pull/9392)
- 🔥 macOS targets now default to `unpacked` split-debuginfo.
[#9298](https://github.com/rust-lang/cargo/pull/9298)
- ❗ The `authors` field is no longer included in `Cargo.toml` for new
projects.
@ -22,8 +52,29 @@
different toolchain versions. There are shared, unversioned files (such as
the search index) that can become broken when using different versions.
[#8640](https://github.com/rust-lang/cargo/pull/8640)
[#9404](https://github.com/rust-lang/cargo/pull/9404)
- Improved error messages when path dependency/workspace member is missing.
[#9368](https://github.com/rust-lang/cargo/pull/9368)
### Fixed
- Fixed `cargo doc` detecting if the documentation needs to be rebuilt when
changing some settings such as features.
[#9419](https://github.com/rust-lang/cargo/pull/9419)
- `cargo doc` now deletes the output directory for the package before running
rustdoc to clear out any stale files.
[#9419](https://github.com/rust-lang/cargo/pull/9419)
- Fixed the `-C metadata` value to always include all information for all
builds. Previously, in some situations, the hash only included the package
name and version. This fixes some issues, such as incremental builds with
split-debuginfo on macOS corrupting the incremental cache in some cases.
[#9418](https://github.com/rust-lang/cargo/pull/9418)
- Fixed man pages not working on Windows if `man` is in `PATH`.
[#9378](https://github.com/rust-lang/cargo/pull/9378)
- The `rustc` cache is now aware of `RUSTC_WRAPPER` and `RUSTC_WORKSPACE_WRAPPER`.
[#9348](https://github.com/rust-lang/cargo/pull/9348)
- Track the `CARGO` environment variable in the rebuild fingerprint if the
code uses `env!("CARGO")`.
[#9363](https://github.com/rust-lang/cargo/pull/9363)
### Nightly only
- Fixed config includes not working.
@ -31,8 +82,19 @@
- Emit note when `--future-incompat-report` had nothing to report.
[#9263](https://github.com/rust-lang/cargo/pull/9263)
- Error messages for nightly features flags (like `-Z` and `cargo-features`)
should now provide more information.
now provides more information.
[#9290](https://github.com/rust-lang/cargo/pull/9290)
- Added the ability to set the target for an individual package in `Cargo.toml`.
[docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#per-package-target)
[#9030](https://github.com/rust-lang/cargo/pull/9030)
- Fixed build-std updating the index on every build.
[#9393](https://github.com/rust-lang/cargo/pull/9393)
- `-Z help` now displays all the `-Z` options.
[#9369](https://github.com/rust-lang/cargo/pull/9369)
- Added `-Zallow-features` to specify which nightly features are allowed to be used.
[#9283](https://github.com/rust-lang/cargo/pull/9283)
- Added `cargo config` subcommand.
[#9302](https://github.com/rust-lang/cargo/pull/9302)
## Cargo 1.52 (2021-05-06)
[34170fcd...rust-1.52.0](https://github.com/rust-lang/cargo/compare/34170fcd...rust-1.52.0)

View File

@ -1,6 +1,6 @@
[package]
name = "cargo"
version = "0.54.0"
version = "0.55.0"
edition = "2018"
authors = ["Yehuda Katz <wycats@gmail.com>",
"Carl Lerche <me@carllerche.com>",
@ -61,7 +61,7 @@ tempfile = "3.0"
termcolor = "1.1"
toml = "0.5.7"
unicode-xid = "0.2.0"
url = "2.0"
url = "2.2.2"
walkdir = "2.2"
clap = "2.31.2"
unicode-width = "0.1.5"

View File

@ -31,8 +31,12 @@ pub fn cargo_test(attr: TokenStream, item: TokenStream) -> TokenStream {
}
};
let mut new_body =
to_token_stream("let _test_guard = cargo_test_support::paths::init_root();");
let mut new_body = to_token_stream(
r#"let _test_guard = {
let tmp_dir = option_env!("CARGO_TARGET_TMPDIR");
cargo_test_support::paths::init_root(tmp_dir)
};"#,
);
// If this is a `build_std` test (aka `tests/build-std/*.rs`) then they
// only run on nightly and they only run when specifically instructed to

View File

@ -21,4 +21,4 @@ remove_dir_all = "0.5"
serde_json = "1.0"
tar = { version = "0.4.18", default-features = false }
toml = "0.5.7"
url = "2.0"
url = "2.2.2"

View File

@ -132,11 +132,12 @@ pub fn init(path: &Path) -> git2::Repository {
}
fn default_search_path() {
use crate::paths::GLOBAL_ROOT;
use crate::paths::global_root;
use git2::{opts::set_search_path, ConfigLevel};
static INIT: Once = Once::new();
INIT.call_once(|| unsafe {
let path = GLOBAL_ROOT.join("blank_git_search_path");
let path = global_root().join("blank_git_search_path");
t!(set_search_path(ConfigLevel::System, &path));
t!(set_search_path(ConfigLevel::Global, &path));
t!(set_search_path(ConfigLevel::XDG, &path));

View File

@ -14,28 +14,44 @@ use std::sync::Mutex;
static CARGO_INTEGRATION_TEST_DIR: &str = "cit";
lazy_static! {
pub static ref GLOBAL_ROOT: PathBuf = {
let mut path = t!(env::current_exe());
path.pop(); // chop off exe name
path.pop(); // chop off 'debug'
// If `cargo test` is run manually then our path looks like
// `target/debug/foo`, in which case our `path` is already pointing at
// `target`. If, however, `cargo test --target $target` is used then the
// output is `target/$target/debug/foo`, so our path is pointing at
// `target/$target`. Here we conditionally pop the `$target` name.
if path.file_name().and_then(|s| s.to_str()) != Some("target") {
path.pop();
}
path.push(CARGO_INTEGRATION_TEST_DIR);
path.mkdir_p();
path
};
// TODO: Use `SyncOnceCell` when stable
static ref GLOBAL_ROOT: Mutex<Option<PathBuf>> = Mutex::new(None);
static ref TEST_ROOTS: Mutex<HashMap<String, PathBuf>> = Default::default();
}
/// This is used when running cargo is pre-CARGO_TARGET_TMPDIR
/// TODO: Remove when CARGO_TARGET_TMPDIR grows old enough.
fn global_root_legacy() -> PathBuf {
let mut path = t!(env::current_exe());
path.pop(); // chop off exe name
path.pop(); // chop off "deps"
path.push("tmp");
path.mkdir_p();
path
}
fn set_global_root(tmp_dir: Option<&'static str>) {
let mut lock = GLOBAL_ROOT.lock().unwrap();
if lock.is_none() {
let mut root = match tmp_dir {
Some(tmp_dir) => PathBuf::from(tmp_dir),
None => global_root_legacy(),
};
root.push(CARGO_INTEGRATION_TEST_DIR);
*lock = Some(root);
}
}
pub fn global_root() -> PathBuf {
let lock = GLOBAL_ROOT.lock().unwrap();
match lock.as_ref() {
Some(p) => p.clone(),
None => unreachable!("GLOBAL_ROOT not set yet"),
}
}
// We need to give each test a unique id. The test name could serve this
// purpose, but the `test` crate doesn't have a way to obtain the current test
// name.[*] Instead, we used the `cargo-test-macro` crate to automatically
@ -52,14 +68,15 @@ pub struct TestIdGuard {
_private: (),
}
pub fn init_root() -> TestIdGuard {
pub fn init_root(tmp_dir: Option<&'static str>) -> TestIdGuard {
static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
TEST_ID.with(|n| *n.borrow_mut() = Some(id));
let guard = TestIdGuard { _private: () };
set_global_root(tmp_dir);
let r = root();
r.rm_rf();
r.mkdir_p();
@ -80,7 +97,10 @@ pub fn root() -> PathBuf {
order to be able to use the crate root.",
)
});
GLOBAL_ROOT.join(&format!("t{}", id))
let mut root = global_root();
root.push(&format!("t{}", id));
root
}
pub fn home() -> PathBuf {

View File

@ -178,12 +178,7 @@ impl RegistryBuilder {
}
if self.replace_crates_io {
init_registry(
registry_path(),
dl_url().into_string(),
api_url(),
api_path(),
);
init_registry(registry_path(), dl_url().into(), api_url(), api_path());
}
if self.alternative {

View File

@ -161,7 +161,7 @@ pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()>
.with_context(|| format!("failed to write `{}`", path.display()))
}
/// Equivalent to [`write`], but does not write anything if the file contents
/// Equivalent to [`write()`], but does not write anything if the file contents
/// are identical to the given contents.
pub fn write_if_changed<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> {
(|| -> Result<()> {
@ -184,7 +184,7 @@ pub fn write_if_changed<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) ->
Ok(())
}
/// Equivalent to [`write`], but appends to the end instead of replacing the
/// Equivalent to [`write()`], but appends to the end instead of replacing the
/// contents.
pub fn append(path: &Path, contents: &[u8]) -> Result<()> {
(|| -> Result<()> {

View File

@ -91,6 +91,16 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]]
name = "form_urlencoded"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
dependencies = [
"matches",
"percent-encoding",
]
[[package]]
name = "generic-array"
version = "0.12.3"
@ -391,10 +401,11 @@ checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "url"
version = "2.1.1"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb"
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
dependencies = [
"form_urlencoded",
"idna",
"matches",
"percent-encoding",

View File

@ -12,7 +12,7 @@ handlebars = { version = "3.2.1", features = ["dir_source"] }
pulldown-cmark = { version = "0.7.2", default-features = false }
same-file = "1.0.6"
serde_json = "1.0.56"
url = "2.1.1"
url = "2.2.2"
[dev-dependencies]
pretty_assertions = "0.6.1"

View File

@ -96,7 +96,7 @@ fn join_url<'a>(base: Option<&Url>, dest: CowStr<'a>) -> CowStr<'a> {
let joined = base_url.join(&dest).unwrap_or_else(|e| {
panic!("failed to join URL `{}` to `{}`: {}", dest, base_url, e)
});
joined.into_string().into()
String::from(joined).into()
}
}
None => dest,

View File

@ -7,7 +7,6 @@ pub fn builtin() -> Vec<App> {
check::cli(),
clean::cli(),
config::cli(),
describe_future_incompatibilities::cli(),
doc::cli(),
fetch::cli(),
fix::cli(),
@ -25,6 +24,7 @@ pub fn builtin() -> Vec<App> {
pkgid::cli(),
publish::cli(),
read_manifest::cli(),
report::cli(),
run::cli(),
rustc::cli(),
rustdoc::cli(),
@ -47,7 +47,6 @@ pub fn builtin_exec(cmd: &str) -> Option<fn(&mut Config, &ArgMatches<'_>) -> Cli
"check" => check::exec,
"clean" => clean::exec,
"config" => config::exec,
"describe-future-incompatibilities" => describe_future_incompatibilities::exec,
"doc" => doc::exec,
"fetch" => fetch::exec,
"fix" => fix::exec,
@ -65,6 +64,7 @@ pub fn builtin_exec(cmd: &str) -> Option<fn(&mut Config, &ArgMatches<'_>) -> Cli
"pkgid" => pkgid::exec,
"publish" => publish::exec,
"read-manifest" => read_manifest::exec,
"report" => report::exec,
"run" => run::exec,
"rustc" => rustc::exec,
"rustdoc" => rustdoc::exec,
@ -87,7 +87,6 @@ pub mod build;
pub mod check;
pub mod clean;
pub mod config;
pub mod describe_future_incompatibilities;
pub mod doc;
pub mod fetch;
pub mod fix;
@ -106,6 +105,7 @@ pub mod package;
pub mod pkgid;
pub mod publish;
pub mod read_manifest;
pub mod report;
pub mod run;
pub mod rustc;
pub mod rustdoc;

View File

@ -5,26 +5,35 @@ use cargo::drop_eprint;
use std::io::Read;
pub fn cli() -> App {
subcommand("describe-future-incompatibilities")
.arg(
opt(
"id",
"identifier of the report [generated by a Cargo command invocation",
)
.value_name("id")
.required(true),
subcommand("report")
.about("Generate and display various kinds of reports")
.after_help("Run `cargo help report` for more detailed information.\n")
.setting(clap::AppSettings::SubcommandRequiredElseHelp)
.subcommand(
subcommand("future-incompatibilities")
.about("Reports any crates which will eventually stop compiling")
.arg(
opt(
"id",
"identifier of the report generated by a Cargo command invocation",
)
.value_name("id")
.required(true),
),
)
.about("Reports any crates which will eventually stop compiling")
}
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
if !config.nightly_features_allowed {
return Err(anyhow!(
"`cargo describe-future-incompatibilities` can only be used on the nightly channel"
)
.into());
return Err(anyhow!("`cargo report` can only be used on the nightly channel").into());
}
match args.subcommand() {
("future-incompatibilities", Some(args)) => report_future_incompatibilies(config, args),
(cmd, _) => panic!("unexpected command `{}`", cmd),
}
}
fn report_future_incompatibilies(config: &Config, args: &ArgMatches<'_>) -> CliResult {
let ws = args.workspace(config)?;
let report_file = ws.target_dir().open_ro(
FUTURE_INCOMPAT_FILE,

View File

@ -75,7 +75,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
if let Some(opt_value) = args.value_of(PRINT_ARG_NAME) {
config
.cli_unstable()
.fail_if_stable_opt(PRINT_ARG_NAME, 8923)?;
.fail_if_stable_opt(PRINT_ARG_NAME, 9357)?;
ops::print(&ws, &compile_opts, opt_value)?;
} else {
ops::compile(&ws, &compile_opts)?;

View File

@ -887,11 +887,11 @@ impl<'cfg> DrainState<'cfg> {
if cx.bcx.build_config.future_incompat_report {
drop_eprint!(cx.bcx.config, "{}", full_report);
drop(cx.bcx.config.shell().note(
&format!("this report can be shown with `cargo describe-future-incompatibilities -Z future-incompat-report --id {}`", id)
&format!("this report can be shown with `cargo report future-incompatibilities -Z future-incompat-report --id {}`", id)
));
} else {
drop(cx.bcx.config.shell().note(
&format!("to see what the problems were, use the option `--future-incompat-report`, or run `cargo describe-future-incompatibilities --id {}`", id)
&format!("to see what the problems were, use the option `--future-incompat-report`, or run `cargo report future-incompatibilities --id {}`", id)
));
}
}

View File

@ -125,6 +125,8 @@ pub struct Layout {
examples: PathBuf,
/// The directory for rustdoc output: `$root/doc`
doc: PathBuf,
/// The directory for temporary data of integration tests and benches: `$dest/tmp`
tmp: PathBuf,
/// The lockfile for a build (`.cargo-lock`). Will be unlocked when this
/// struct is `drop`ped.
_lock: FileLock,
@ -170,6 +172,7 @@ impl Layout {
fingerprint: dest.join(".fingerprint"),
examples: dest.join("examples"),
doc: root.join("doc"),
tmp: dest.join("tmp"),
root,
dest,
_lock: lock,
@ -219,4 +222,9 @@ impl Layout {
pub fn build(&self) -> &Path {
&self.build
}
/// Create and return the tmp path.
pub fn prepare_tmp(&self) -> CargoResult<&Path> {
paths::create_dir_all(&self.tmp)?;
Ok(&self.tmp)
}
}

View File

@ -581,6 +581,11 @@ fn prepare_rustc(
base.env("CARGO_PRIMARY_PACKAGE", "1");
}
if unit.target.is_test() || unit.target.is_bench() {
let tmp = cx.files().layout(unit.kind).prepare_tmp()?;
base.env("CARGO_TARGET_TMPDIR", tmp.display().to_string());
}
if cx.bcx.config.cli_unstable().jobserver_per_rustc {
let client = cx.new_jobserver()?;
base.inherit_jobserver(&client);

View File

@ -62,7 +62,7 @@
//!
//! 1. Add the option to the [`CliUnstable`] struct below. Flags can take an
//! optional value if you want.
//! 2. Update the [`CliUnstable::add`] function to parse the flag.
//! 2. Update the [`CliUnstable::add`][CliUnstable] function to parse the flag.
//! 3. Wherever the new functionality is implemented, call
//! [`Config::cli_unstable`][crate::util::config::Config::cli_unstable] to
//! get an instance of `CliUnstable` and check if the option has been
@ -81,8 +81,8 @@
//! macro below.
//! 2. `-Z unstable-options`: Find the call to `fail_if_stable_opt` and
//! remove it. Be sure to update the man pages if necessary.
//! 3. `-Z` flag: Change the parsing code in [`CliUnstable::add`] to call
//! `stabilized_warn` or `stabilized_err` and remove the field from
//! 3. `-Z` flag: Change the parsing code in [`CliUnstable::add`][CliUnstable]
//! to call `stabilized_warn` or `stabilized_err` and remove the field from
//! `CliUnstable. Remove the `(unstable)` note in the clap help text if
//! necessary.
//! 2. Remove `masquerade_as_nightly_cargo` from any tests, and remove

View File

@ -31,11 +31,22 @@ struct PackageIdInner {
source_id: SourceId,
}
// Custom equality that uses full equality of SourceId, rather than its custom equality.
// Custom equality that uses full equality of SourceId, rather than its custom equality,
// and Version, which usually ignores `build` metadata.
//
// The `build` part of the version is usually ignored (like a "comment").
// However, there are some cases where it is important. The download path from
// a registry includes the build metadata, and Cargo uses PackageIds for
// creating download paths. Including it here prevents the PackageId interner
// from getting poisoned with PackageIds where that build metadata is missing.
impl PartialEq for PackageIdInner {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
&& self.version == other.version
&& self.version.major == other.version.major
&& self.version.minor == other.version.minor
&& self.version.patch == other.version.patch
&& self.version.pre == other.version.pre
&& self.version.build == other.version.build
&& self.source_id.full_eq(other.source_id)
}
}
@ -44,7 +55,11 @@ impl PartialEq for PackageIdInner {
impl Hash for PackageIdInner {
fn hash<S: hash::Hasher>(&self, into: &mut S) {
self.name.hash(into);
self.version.hash(into);
self.version.major.hash(into);
self.version.minor.hash(into);
self.version.patch.hash(into);
self.version.pre.hash(into);
self.version.build.hash(into);
self.source_id.full_hash(into);
}
}
@ -97,6 +112,8 @@ impl PartialEq for PackageId {
if ptr::eq(self.inner, other.inner) {
return true;
}
// This is here so that PackageId uses SourceId's and Version's idea
// of equality. PackageIdInner uses a more exact notion of equality.
self.inner.name == other.inner.name
&& self.inner.version == other.inner.version
&& self.inner.source_id == other.inner.source_id
@ -105,6 +122,9 @@ impl PartialEq for PackageId {
impl Hash for PackageId {
fn hash<S: hash::Hasher>(&self, state: &mut S) {
// This is here (instead of derived) so that PackageId uses SourceId's
// and Version's idea of equality. PackageIdInner uses a more exact
// notion of hashing.
self.inner.name.hash(state);
self.inner.version.hash(state);
self.inner.source_id.hash(state);
@ -166,6 +186,12 @@ impl PackageId {
}
}
/// Returns a value that implements a "stable" hashable value.
///
/// Stable hashing removes the path prefix of the workspace from path
/// packages. This helps with reproducible builds, since this hash is part
/// of the symbol metadata, and we don't want the absolute path where the
/// build is performed to affect the binary output.
pub fn stable_hash(self, workspace: &Path) -> PackageIdStableHash<'_> {
PackageIdStableHash(self, workspace)
}

View File

@ -517,6 +517,8 @@ struct IgnoreList {
ignore: Vec<String>,
/// mercurial formatted entries
hg_ignore: Vec<String>,
/// Fossil-formatted entries.
fossil_ignore: Vec<String>,
}
impl IgnoreList {
@ -525,15 +527,17 @@ impl IgnoreList {
IgnoreList {
ignore: Vec::new(),
hg_ignore: Vec::new(),
fossil_ignore: Vec::new(),
}
}
/// add a new entry to the ignore list. Requires two arguments with the
/// entry in two different formats. One for "git style" entries and one for
/// "mercurial like" entries.
fn push(&mut self, ignore: &str, hg_ignore: &str) {
/// Add a new entry to the ignore list. Requires three arguments with the
/// entry in possibly three different formats. One for "git style" entries,
/// one for "mercurial style" entries and one for "fossil style" entries.
fn push(&mut self, ignore: &str, hg_ignore: &str, fossil_ignore: &str) {
self.ignore.push(ignore.to_string());
self.hg_ignore.push(hg_ignore.to_string());
self.fossil_ignore.push(fossil_ignore.to_string());
}
/// Return the correctly formatted content of the ignore file for the given
@ -541,6 +545,7 @@ impl IgnoreList {
fn format_new(&self, vcs: VersionControl) -> String {
let ignore_items = match vcs {
VersionControl::Hg => &self.hg_ignore,
VersionControl::Fossil => &self.fossil_ignore,
_ => &self.ignore,
};
@ -557,20 +562,30 @@ impl IgnoreList {
let ignore_items = match vcs {
VersionControl::Hg => &self.hg_ignore,
VersionControl::Fossil => &self.fossil_ignore,
_ => &self.ignore,
};
let mut out = "\n\n# Added by cargo\n".to_string();
if ignore_items
.iter()
.any(|item| existing_items.contains(item))
{
out.push_str("#\n# already existing elements were commented out\n");
let mut out = String::new();
// Fossil does not support `#` comments.
if vcs != VersionControl::Fossil {
out.push_str("\n\n# Added by cargo\n");
if ignore_items
.iter()
.any(|item| existing_items.contains(item))
{
out.push_str("#\n# already existing elements were commented out\n");
}
out.push('\n');
}
out.push('\n');
for item in ignore_items {
if existing_items.contains(item) {
if vcs == VersionControl::Fossil {
// Just merge for Fossil.
continue;
}
out.push('#');
}
out.push_str(item);
@ -584,30 +599,35 @@ impl IgnoreList {
/// Writes the ignore file to the given directory. If the ignore file for the
/// given vcs system already exists, its content is read and duplicate ignore
/// file entries are filtered out.
fn write_ignore_file(
base_path: &Path,
list: &IgnoreList,
vcs: VersionControl,
) -> CargoResult<String> {
let fp_ignore = match vcs {
VersionControl::Git => base_path.join(".gitignore"),
VersionControl::Hg => base_path.join(".hgignore"),
VersionControl::Pijul => base_path.join(".ignore"),
VersionControl::Fossil => return Ok("".to_string()),
VersionControl::NoVcs => return Ok("".to_string()),
};
fn write_ignore_file(base_path: &Path, list: &IgnoreList, vcs: VersionControl) -> CargoResult<()> {
// Fossil only supports project-level settings in a dedicated subdirectory.
if vcs == VersionControl::Fossil {
paths::create_dir_all(base_path.join(".fossil-settings"))?;
}
let ignore: String = match paths::open(&fp_ignore) {
Err(err) => match err.downcast_ref::<std::io::Error>() {
Some(io_err) if io_err.kind() == ErrorKind::NotFound => list.format_new(vcs),
_ => return Err(err),
},
Ok(file) => list.format_existing(BufReader::new(file), vcs),
};
for fp_ignore in match vcs {
VersionControl::Git => vec![base_path.join(".gitignore")],
VersionControl::Hg => vec![base_path.join(".hgignore")],
VersionControl::Pijul => vec![base_path.join(".ignore")],
// Fossil has a cleaning functionality configured in a separate file.
VersionControl::Fossil => vec![
base_path.join(".fossil-settings/ignore-glob"),
base_path.join(".fossil-settings/clean-glob"),
],
VersionControl::NoVcs => return Ok(()),
} {
let ignore: String = match paths::open(&fp_ignore) {
Err(err) => match err.downcast_ref::<std::io::Error>() {
Some(io_err) if io_err.kind() == ErrorKind::NotFound => list.format_new(vcs),
_ => return Err(err),
},
Ok(file) => list.format_existing(BufReader::new(file), vcs),
};
paths::append(&fp_ignore, ignore.as_bytes())?;
paths::append(&fp_ignore, ignore.as_bytes())?;
}
Ok(ignore)
Ok(())
}
/// Initializes the correct VCS system based on the provided config.
@ -650,12 +670,12 @@ fn mk(config: &Config, opts: &MkOptions<'_>) -> CargoResult<()> {
let name = opts.name;
let cfg = config.get::<CargoNewConfig>("cargo-new")?;
// Using the push method with two arguments ensures that the entries for
// both `ignore` and `hgignore` are in sync.
// Using the push method with multiple arguments ensures that the entries
// for all mutually-incompatible VCS in terms of syntax are in sync.
let mut ignore = IgnoreList::new();
ignore.push("/target", "^target/");
ignore.push("/target", "^target/", "target");
if !opts.bin {
ignore.push("Cargo.lock", "glob:Cargo.lock");
ignore.push("Cargo.lock", "glob:Cargo.lock", "Cargo.lock,*/Cargo.lock");
}
let vcs = opts.version_control.unwrap_or_else(|| {

View File

@ -394,52 +394,31 @@ fn check_repo_state(
src_files: &[PathBuf],
repo: &git2::Repository,
) -> CargoResult<Option<String>> {
let workdir = repo.workdir().unwrap();
// This is a collection of any dirty or untracked files. This covers:
// - new/modified/deleted/renamed/type change (index or worktree)
// - untracked files (which are "new" worktree files)
// - ignored (in case the user has an `include` directive that
// conflicts with .gitignore).
let mut dirty_files = Vec::new();
collect_statuses(repo, &mut dirty_files)?;
// Include each submodule so that the error message can provide
// specifically *which* files in a submodule are modified.
status_submodules(repo, &mut dirty_files)?;
let mut sub_repos = Vec::new();
open_submodules(repo, &mut sub_repos)?;
// Sort so that longest paths are first, to check nested submodules first.
sub_repos.sort_unstable_by(|a, b| b.0.as_os_str().len().cmp(&a.0.as_os_str().len()));
let submodule_dirty = |path: &Path| -> bool {
sub_repos
.iter()
.filter(|(sub_path, _sub_repo)| path.starts_with(sub_path))
.any(|(sub_path, sub_repo)| {
let relative = path.strip_prefix(sub_path).unwrap();
sub_repo
.status_file(relative)
.map(|status| status != git2::Status::CURRENT)
.unwrap_or(false)
})
};
let dirty = src_files
// Find the intersection of dirty in git, and the src_files that would
// be packaged. This is a lazy n^2 check, but seems fine with
// thousands of files.
let dirty_src_files: Vec<String> = src_files
.iter()
.filter(|file| {
let relative = file.strip_prefix(workdir).unwrap();
if let Ok(status) = repo.status_file(relative) {
if status == git2::Status::CURRENT {
false
} else if relative.file_name().and_then(|s| s.to_str()).unwrap_or("")
== "Cargo.lock"
{
// It is OK to include this file even if it is ignored.
status != git2::Status::IGNORED
} else {
true
}
} else {
submodule_dirty(file)
}
})
.filter(|src_file| dirty_files.iter().any(|path| src_file.starts_with(path)))
.map(|path| {
path.strip_prefix(p.root())
.unwrap_or(path)
.display()
.to_string()
})
.collect::<Vec<_>>();
if dirty.is_empty() {
.collect();
if dirty_src_files.is_empty() {
let rev_obj = repo.revparse_single("HEAD")?;
Ok(Some(rev_obj.id().to_string()))
} else {
@ -447,23 +426,57 @@ fn check_repo_state(
"{} files in the working directory contain changes that were \
not yet committed into git:\n\n{}\n\n\
to proceed despite this and include the uncommitted changes, pass the `--allow-dirty` flag",
dirty.len(),
dirty.join("\n")
dirty_src_files.len(),
dirty_src_files.join("\n")
)
}
}
/// Helper to recursively open all submodules.
fn open_submodules(
// Helper to collect dirty statuses for a single repo.
fn collect_statuses(
repo: &git2::Repository,
sub_repos: &mut Vec<(PathBuf, git2::Repository)>,
dirty_files: &mut Vec<PathBuf>,
) -> CargoResult<()> {
let mut status_opts = git2::StatusOptions::new();
// Exclude submodules, as they are being handled manually by recursing
// into each one so that details about specific files can be
// retrieved.
status_opts
.exclude_submodules(true)
.include_ignored(true)
.include_untracked(true);
let repo_statuses = repo.statuses(Some(&mut status_opts)).with_context(|| {
format!(
"failed to retrieve git status from repo {}",
repo.path().display()
)
})?;
let workdir = repo.workdir().unwrap();
let this_dirty = repo_statuses.iter().filter_map(|entry| {
let path = entry.path().expect("valid utf-8 path");
if path.ends_with("Cargo.lock") && entry.status() == git2::Status::IGNORED {
// It is OK to include Cargo.lock even if it is ignored.
return None;
}
// Use an absolute path, so that comparing paths is easier
// (particularly with submodules).
Some(workdir.join(path))
});
dirty_files.extend(this_dirty);
Ok(())
}
// Helper to collect dirty statuses while recursing into submodules.
fn status_submodules(
repo: &git2::Repository,
dirty_files: &mut Vec<PathBuf>,
) -> CargoResult<()> {
for submodule in repo.submodules()? {
// Ignore submodules that don't open, they are probably not initialized.
// If its files are required, then the verification step should fail.
if let Ok(sub_repo) = submodule.open() {
open_submodules(&sub_repo, sub_repos)?;
sub_repos.push((sub_repo.workdir().unwrap().to_owned(), sub_repo));
status_submodules(&sub_repo, dirty_files)?;
collect_statuses(&sub_repo, dirty_files)?;
}
}
Ok(())

View File

@ -3,7 +3,7 @@
use crate::core::GitReference;
use crate::util::errors::CargoResult;
use crate::util::{network, Config, IntoUrl, Progress};
use crate::util::{network, Config, IntoUrl, MetricsCounter, Progress};
use anyhow::{anyhow, Context as _};
use cargo_util::{paths, ProcessBuilder};
use curl::easy::List;
@ -15,6 +15,7 @@ use std::env;
use std::fmt;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::time::{Duration, Instant};
use url::Url;
fn serialize_str<T, S>(t: &T, s: S) -> Result<S::Ok, S::Error>
@ -677,7 +678,7 @@ fn reset(repo: &git2::Repository, obj: &git2::Object<'_>, config: &Config) -> Ca
let mut pb = Progress::new("Checkout", config);
let mut opts = git2::build::CheckoutBuilder::new();
opts.progress(|_, cur, max| {
drop(pb.tick(cur, max));
drop(pb.tick(cur, max, ""));
});
debug!("doing reset");
repo.reset(obj, git2::ResetType::Hard, Some(&mut opts))?;
@ -694,12 +695,49 @@ pub fn with_fetch_options(
let mut progress = Progress::new("Fetch", config);
network::with_retry(config, || {
with_authentication(url, git_config, |f| {
let mut last_update = Instant::now();
let mut rcb = git2::RemoteCallbacks::new();
// We choose `N=10` here to make a `300ms * 10slots ~= 3000ms`
// sliding window for tracking the data transfer rate (in bytes/s).
let mut counter = MetricsCounter::<10>::new(0, last_update);
rcb.credentials(f);
rcb.transfer_progress(|stats| {
let indexed_deltas = stats.indexed_deltas();
let msg = if indexed_deltas > 0 {
// Resolving deltas.
format!(
", ({}/{}) resolving deltas",
indexed_deltas,
stats.total_deltas()
)
} else {
// Receiving objects.
//
// # Caveat
//
// Progress bar relies on git2 calling `transfer_progress`
// to update its transfer rate, but we cannot guarantee a
// periodic call of that callback. Thus if we don't receive
// any data for, say, 10 seconds, the rate will get stuck
// and never go down to 0B/s.
// In the future, we need to find away to update the rate
// even when the callback is not called.
let now = Instant::now();
// Scrape a `received_bytes` to the counter every 300ms.
if now - last_update > Duration::from_millis(300) {
counter.add(stats.received_bytes(), now);
last_update = now;
}
fn format_bytes(bytes: f32) -> (&'static str, f32) {
static UNITS: [&str; 5] = ["", "Ki", "Mi", "Gi", "Ti"];
let i = (bytes.log2() / 10.0).min(4.0) as usize;
(UNITS[i], bytes / 1024_f32.powi(i as i32))
}
let (unit, rate) = format_bytes(counter.rate());
format!(", {:.2}{}B/s", rate, unit)
};
progress
.tick(stats.indexed_objects(), stats.total_objects())
.tick(stats.indexed_objects(), stats.total_objects(), &msg)
.is_ok()
});

View File

@ -108,8 +108,17 @@ impl<'cfg> PathSource<'cfg> {
fn _list_files(&self, pkg: &Package) -> CargoResult<Vec<PathBuf>> {
let root = pkg.root();
let no_include_option = pkg.manifest().include().is_empty();
let git_repo = if no_include_option {
self.discover_git_repo(root)?
} else {
None
};
let mut exclude_builder = GitignoreBuilder::new(root);
if no_include_option && git_repo.is_none() {
// no include option and not git repo discovered (see rust-lang/cargo#7183).
exclude_builder.add_line(None, ".*")?;
}
for rule in pkg.manifest().exclude() {
exclude_builder.add_line(None, rule)?;
}
@ -161,23 +170,16 @@ impl<'cfg> PathSource<'cfg> {
// Attempt Git-prepopulate only if no `include` (see rust-lang/cargo#4135).
if no_include_option {
if let Some(result) = self.discover_git_and_list_files(pkg, root, &mut filter)? {
return Ok(result);
if let Some(repo) = git_repo {
return self.list_files_git(pkg, &repo, &mut filter);
}
// no include option and not git repo discovered (see rust-lang/cargo#7183).
return self.list_files_walk_except_dot_files_and_dirs(pkg, &mut filter);
}
self.list_files_walk(pkg, &mut filter)
}
// Returns `Some(_)` if found sibling `Cargo.toml` and `.git` directory;
// otherwise, caller should fall back on full file list.
fn discover_git_and_list_files(
&self,
pkg: &Package,
root: &Path,
filter: &mut dyn FnMut(&Path, bool) -> CargoResult<bool>,
) -> CargoResult<Option<Vec<PathBuf>>> {
/// Returns `Some(git2::Repository)` if found sibling `Cargo.toml` and `.git`
/// directory; otherwise, caller should fall back on full file list.
fn discover_git_repo(&self, root: &Path) -> CargoResult<Option<git2::Repository>> {
let repo = match git2::Repository::discover(root) {
Ok(repo) => repo,
Err(e) => {
@ -212,7 +214,7 @@ impl<'cfg> PathSource<'cfg> {
};
let manifest_path = repo_relative_path.join("Cargo.toml");
if index.get_path(&manifest_path, 0).is_some() {
return Ok(Some(self.list_files_git(pkg, &repo, filter)?));
return Ok(Some(repo));
}
// Package Cargo.toml is not in git, don't use git to guide our selection.
Ok(None)
@ -356,27 +358,6 @@ impl<'cfg> PathSource<'cfg> {
}
}
fn list_files_walk_except_dot_files_and_dirs(
&self,
pkg: &Package,
filter: &mut dyn FnMut(&Path, bool) -> CargoResult<bool>,
) -> CargoResult<Vec<PathBuf>> {
let root = pkg.root();
let mut exclude_dot_files_dir_builder = GitignoreBuilder::new(root);
exclude_dot_files_dir_builder.add_line(None, ".*")?;
let ignore_dot_files_and_dirs = exclude_dot_files_dir_builder.build()?;
let mut filter_ignore_dot_files_and_dirs =
|path: &Path, is_dir: bool| -> CargoResult<bool> {
let relative_path = path.strip_prefix(root)?;
match ignore_dot_files_and_dirs.matched_path_or_any_parents(relative_path, is_dir) {
Match::Ignore(_) => Ok(false),
_ => filter(path, is_dir),
}
};
self.list_files_walk(pkg, &mut filter_ignore_dot_files_and_dirs)
}
fn list_files_walk(
&self,
pkg: &Package,

View File

@ -692,8 +692,16 @@ impl Summaries {
// * `2`: Added the "index format version" field so that if the index format
// changes, different versions of cargo won't get confused reading each
// other's caches.
// * `3`: Bumped the version to work around a issue where multiple versions of
// a package were published that differ only by semver metadata. For
// example, openssl-src 110.0.0 and 110.0.0+1.1.0f. Previously, the cache
// would be incorrectly populated with two entries, both 110.0.0. After
// this, the metadata will be correctly included. This isn't really a format
// change, just a version bump to clear the incorrect cache entries. Note:
// the index shouldn't allow these, but unfortunately crates.io doesn't
// check it.
const CURRENT_CACHE_VERSION: u8 = 2;
const CURRENT_CACHE_VERSION: u8 = 3;
impl<'a> SummariesCache<'a> {
fn parse(data: &'a [u8], last_index_update: &str) -> CargoResult<SummariesCache<'a>> {

View File

@ -189,8 +189,8 @@ const VERSION_TEMPLATE: &str = "{version}";
const PREFIX_TEMPLATE: &str = "{prefix}";
const LOWER_PREFIX_TEMPLATE: &str = "{lowerprefix}";
/// A "source" for a [local](local::LocalRegistry) or
/// [remote](remote::RemoteRegistry) registry.
/// A "source" for a local (see `local::LocalRegistry`) or remote (see
/// `remote::RemoteRegistry`) registry.
///
/// This contains common functionality that is shared between the two registry
/// kinds, with the registry-specific logic implemented as part of the
@ -415,8 +415,8 @@ impl<'a> RegistryDependency<'a> {
}
}
/// An abstract interface to handle both a [local](local::LocalRegistry) and
/// [remote](remote::RemoteRegistry) registry.
/// An abstract interface to handle both a local (see `local::LocalRegistry`)
/// and remote (see `remote::RemoteRegistry`) registry.
///
/// This allows [`RegistrySource`] to abstractly handle both registry kinds.
pub trait RegistryData {
@ -460,9 +460,9 @@ pub trait RegistryData {
/// Despite the name, this doesn't actually download anything. If the
/// `.crate` is already downloaded, then it returns [`MaybeLock::Ready`].
/// If it hasn't been downloaded, then it returns [`MaybeLock::Download`]
/// which contains the URL to download. The [`crate::core::package::Download`]
/// which contains the URL to download. The [`crate::core::package::Downloads`]
/// system handles the actual download process. After downloading, it
/// calls [`finish_download`] to save the downloaded file.
/// calls [`Self::finish_download`] to save the downloaded file.
///
/// `checksum` is currently only used by local registries to verify the
/// file contents (because local registries never actually download
@ -474,7 +474,7 @@ pub trait RegistryData {
/// Finish a download by saving a `.crate` file to disk.
///
/// After [`crate::core::package::Download`] has finished a download,
/// After [`crate::core::package::Downloads`] has finished a download,
/// it will call this to save the `.crate` file. This is only relevant
/// for remote registries. This should validate the checksum and save
/// the given data to the on-disk cache.

View File

@ -485,7 +485,6 @@ pub trait ArgMatchesExt {
if build_config.future_incompat_report {
config
.cli_unstable()
// TODO: Tracking issue
.fail_if_stable_opt("--future-incompat-report", 9241)?;
if !config.cli_unstable().future_incompat_report {

67
src/cargo/util/counter.rs Normal file
View File

@ -0,0 +1,67 @@
use std::time::Instant;
/// A metrics counter storing only latest `N` records.
pub struct MetricsCounter<const N: usize> {
/// Slots to store metrics.
slots: [(usize, Instant); N],
/// The slot of the oldest record.
/// Also the next slot to store the new record.
index: usize,
}
impl<const N: usize> MetricsCounter<N> {
/// Creates a new counter with an initial value.
pub fn new(init: usize, init_at: Instant) -> Self {
assert!(N > 0, "number of slots must be greater than zero");
Self {
slots: [(init, init_at); N],
index: 0,
}
}
/// Adds record to the counter.
pub fn add(&mut self, data: usize, added_at: Instant) {
self.slots[self.index] = (data, added_at);
self.index = (self.index + 1) % N;
}
/// Calculates per-second average rate of all slots.
pub fn rate(&self) -> f32 {
let latest = self.slots[self.index.checked_sub(1).unwrap_or(N - 1)];
let oldest = self.slots[self.index];
let duration = (latest.1 - oldest.1).as_secs_f32();
let avg = (latest.0 - oldest.0) as f32 / duration;
if f32::is_nan(avg) {
0f32
} else {
avg
}
}
}
#[cfg(test)]
mod tests {
use super::MetricsCounter;
use std::time::{Duration, Instant};
#[test]
fn counter() {
let now = Instant::now();
let mut counter = MetricsCounter::<3>::new(0, now);
assert_eq!(counter.rate(), 0f32);
counter.add(1, now + Duration::from_secs(1));
assert_eq!(counter.rate(), 1f32);
counter.add(4, now + Duration::from_secs(2));
assert_eq!(counter.rate(), 2f32);
counter.add(7, now + Duration::from_secs(3));
assert_eq!(counter.rate(), 3f32);
counter.add(12, now + Duration::from_secs(4));
assert_eq!(counter.rate(), 4f32);
}
#[test]
#[should_panic(expected = "number of slots must be greater than zero")]
fn counter_zero_slot() {
let _counter = MetricsCounter::<0>::new(0, Instant::now());
}
}

View File

@ -3,6 +3,7 @@ use std::time::Duration;
pub use self::canonical_url::CanonicalUrl;
pub use self::config::{homedir, Config, ConfigValue};
pub(crate) use self::counter::MetricsCounter;
pub use self::dependency_queue::DependencyQueue;
pub use self::diagnostic_server::RustfixDiagnosticServer;
pub use self::errors::{internal, CargoResult, CliResult, Test};
@ -29,6 +30,7 @@ pub use self::workspace::{
mod canonical_url;
pub mod command_prelude;
pub mod config;
mod counter;
pub mod cpu;
mod dependency_queue;
pub mod diagnostic_server;

View File

@ -96,7 +96,7 @@ impl<'cfg> Progress<'cfg> {
Self::with_style(name, ProgressStyle::Percentage, cfg)
}
pub fn tick(&mut self, cur: usize, max: usize) -> CargoResult<()> {
pub fn tick(&mut self, cur: usize, max: usize, msg: &str) -> CargoResult<()> {
let s = match &mut self.state {
Some(s) => s,
None => return Ok(()),
@ -118,7 +118,7 @@ impl<'cfg> Progress<'cfg> {
return Ok(());
}
s.tick(cur, max, "")
s.tick(cur, max, msg)
}
pub fn tick_now(&mut self, cur: usize, max: usize, msg: &str) -> CargoResult<()> {

View File

@ -395,7 +395,7 @@ impl<'de> de::Deserialize<'de> for TomlOptLevel {
Ok(TomlOptLevel(value.to_string()))
} else {
Err(E::custom(format!(
"must be an integer, `z`, or `s`, \
"must be `0`, `1`, `2`, `3`, `s` or `z`, \
but found the string: \"{}\"",
value
)))
@ -553,7 +553,7 @@ impl TomlProfile {
if let Some(panic) = &self.panic {
if panic != "unwind" && panic != "abort" {
bail!(
"`panic` setting of `{}` is not a valid setting,\
"`panic` setting of `{}` is not a valid setting, \
must be `unwind` or `abort`",
panic
);

View File

@ -95,21 +95,6 @@ impl FossilRepo {
.arg(db_fname)
.exec()?;
// set `target` as ignoreable and cleanable
ProcessBuilder::new("fossil")
.cwd(cwd)
.arg("settings")
.arg("ignore-glob")
.arg("target")
.exec()?;
ProcessBuilder::new("fossil")
.cwd(cwd)
.arg("settings")
.arg("clean-glob")
.arg("target")
.exec()?;
Ok(FossilRepo)
}
}

View File

@ -1,3 +1,6 @@
[book]
title = "Cargo Contributor Guide"
authors = ["Eric Huss"]
[output.html]
git-repository-url = "https://github.com/rust-lang/cargo/tree/master/src/doc/contrib/src"

View File

@ -70,3 +70,35 @@ This is a very high-level overview of the Cargo codebase.
* [`crates`](https://github.com/rust-lang/cargo/tree/master/crates)
 A collection of independent crates used by Cargo.
## Extra crates
Some functionality is split off into separate crates, usually in the
[`crates`](https://github.com/rust-lang/cargo/tree/master/crates) directory.
* [`cargo-platform`](https://github.com/rust-lang/cargo/tree/master/crates/cargo-platform)
 This library handles parsing `cfg` expressions.
* [`cargo-test-macro`](https://github.com/rust-lang/cargo/tree/master/crates/cargo-test-macro)
 This is a proc-macro used by the test suite to define tests. More
information can be found at [`cargo_test`
attribute](../tests/writing.md#cargo_test-attribute).
* [`cargo-test-support`](https://github.com/rust-lang/cargo/tree/master/crates/cargo-test-support)
 This contains a variety of code to support [writing
tests](../tests/writing.md).
* [`cargo-util`](https://github.com/rust-lang/cargo/tree/master/crates/cargo-util)
 This contains general utility code that is shared between cargo and the
testsuite.
* [`crates-io`](https://github.com/rust-lang/cargo/tree/master/crates/crates-io)
— This contains code for accessing the crates.io API.
* [`credential`](https://github.com/rust-lang/cargo/tree/master/crates/credential)
— This subdirectory contains several packages for implementing the
experimental
[credential-process](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process)
feature.
* [`mdman`](https://github.com/rust-lang/cargo/tree/master/crates/mdman) —
This is a utility for generating cargo's man pages. See [Building the man
pages](https://github.com/rust-lang/cargo/tree/master/src/doc#building-the-man-pages)
for more information.
* [`resolver-tests`](https://github.com/rust-lang/cargo/tree/master/crates/resolver-tests)
 This is a dedicated package that defines tests for the [dependency
resolver](../architecture/packages.md#resolver).

View File

@ -19,9 +19,12 @@ the two dashes (`--`) are passed to the benchmark binaries and thus to
_libtest_ (rustc's built in unit-test and micro-benchmarking framework). If
you are passing arguments to both Cargo and the binary, the ones after `--` go
to the binary, the ones before go to Cargo. For details about libtest's
arguments see the output of `cargo bench -- --help`. As an example, this will
run only the benchmark named `foo` (and skip other similarly named benchmarks
like `foobar`):
arguments see the output of `cargo bench -- --help` and check out the rustc
book's chapter on how tests work at
<https://doc.rust-lang.org/rustc/tests/index.html>.
As an example, this will run only the benchmark named `foo` (and skip other
similarly named benchmarks like `foobar`):
cargo bench -- foo --exact

View File

@ -19,7 +19,8 @@ dashes (`--`) are passed to the test binaries and thus to _libtest_ (rustc's
built in unit-test and micro-benchmarking framework). If you're passing
arguments to both Cargo and the binary, the ones after `--` go to the binary,
the ones before go to Cargo. For details about libtest's arguments see the
output of `cargo test -- --help`.
output of `cargo test -- --help` and check out the rustc book's chapter on
how tests work at <https://doc.rust-lang.org/rustc/tests/index.html>.
As an example, this will filter for tests with `foo` in their name and run them
on 3 threads in parallel:

View File

@ -15,8 +15,11 @@ DESCRIPTION
framework). If you are passing arguments to both Cargo and the binary,
the ones after -- go to the binary, the ones before go to Cargo. For
details about libtest's arguments see the output of cargo bench --
--help. As an example, this will run only the benchmark named foo (and
skip other similarly named benchmarks like foobar):
--help and check out the rustc book's chapter on how tests work at
<https://doc.rust-lang.org/rustc/tests/index.html>.
As an example, this will run only the benchmark named foo (and skip
other similarly named benchmarks like foobar):
cargo bench -- foo --exact

View File

@ -14,7 +14,9 @@ DESCRIPTION
(rustc's built in unit-test and micro-benchmarking framework). If you're
passing arguments to both Cargo and the binary, the ones after -- go to
the binary, the ones before go to Cargo. For details about libtest's
arguments see the output of cargo test -- --help.
arguments see the output of cargo test -- --help and check out the rustc
book's chapter on how tests work at
<https://doc.rust-lang.org/rustc/tests/index.html>.
As an example, this will filter for tests with foo in their name and run
them on 3 threads in parallel:

View File

@ -19,9 +19,12 @@ the two dashes (`--`) are passed to the benchmark binaries and thus to
_libtest_ (rustc's built in unit-test and micro-benchmarking framework). If
you are passing arguments to both Cargo and the binary, the ones after `--` go
to the binary, the ones before go to Cargo. For details about libtest's
arguments see the output of `cargo bench -- --help`. As an example, this will
run only the benchmark named `foo` (and skip other similarly named benchmarks
like `foobar`):
arguments see the output of `cargo bench -- --help` and check out the rustc
book's chapter on how tests work at
<https://doc.rust-lang.org/rustc/tests/index.html>.
As an example, this will run only the benchmark named `foo` (and skip other
similarly named benchmarks like `foobar`):
cargo bench -- foo --exact

View File

@ -19,7 +19,8 @@ dashes (`--`) are passed to the test binaries and thus to _libtest_ (rustc's
built in unit-test and micro-benchmarking framework). If you're passing
arguments to both Cargo and the binary, the ones after `--` go to the binary,
the ones before go to Cargo. For details about libtest's arguments see the
output of `cargo test -- --help`.
output of `cargo test -- --help` and check out the rustc book's chapter on
how tests work at <https://doc.rust-lang.org/rustc/tests/index.html>.
As an example, this will filter for tests with `foo` in their name and run them
on 3 threads in parallel:

View File

@ -125,7 +125,7 @@ compatibility). If Cargo used all of the dependencies' `Cargo.lock` files,
then multiple copies of the library could be used, and perhaps even a version
conflict.
In other words, libraries specify semver requirements for their dependencies but
In other words, libraries specify SemVer requirements for their dependencies but
cannot see the full picture. Only end products like binaries have a full
picture to decide what versions of dependencies should be used.
@ -165,7 +165,7 @@ are often surprised when Cargo attempts to fetch resources from the network, and
hence the request for Cargo to work offline comes up frequently.
Cargo, at its heart, will not attempt to access the network unless told to do
so. That is, if no crates comes from crates.io, a git repository, or some other
so. That is, if no crates come from crates.io, a git repository, or some other
network location, Cargo will never attempt to make a network connection. As a
result, if Cargo attempts to touch the network, then it's because it needs to
fetch a required resource.
@ -204,7 +204,7 @@ replacement][replace].
### Why is Cargo rebuilding my code?
Cargo is responsible for incrementally compiling crates in your project. This
means that if you type `cargo build` twice the second one shouldn't rebuild you
means that if you type `cargo build` twice the second one shouldn't rebuild your
crates.io dependencies, for example. Nevertheless bugs arise and Cargo can
sometimes rebuild code when you're not expecting it!
@ -245,7 +245,7 @@ Some issues we've seen historically which can cause crates to get rebuilt are:
uses timestamps on files to govern whether rebuilding needs to happen, but if
you're using a nonstandard filesystem it may be affecting the timestamps
somehow (e.g. truncating them, causing them to drift, etc). In this scenario,
feel free to open an issue and we can see if we can accomodate the filesystem
feel free to open an issue and we can see if we can accommodate the filesystem
somehow.
* A concurrent build process is either deleting artifacts or modifying files.

View File

@ -55,7 +55,7 @@ invocation. Furthermore, Cargo will automatically fetch from a
[*registry*][def-registry] any dependencies we have defined for our artifact,
and arrange for them to be incorporated into our build as needed.
It is only a slight exageration to say that once you know how to build one
It is only a slight exaggeration to say that once you know how to build one
Cargo-based project, you know how to build *all* of them.
[def-artifact]: ../appendix/glossary.md#artifact '"artifact" (glossary entry)'

View File

@ -94,12 +94,14 @@ There are two styles of tests within a Cargo project:
access to its *public* API.
Tests are run with the [`cargo test`] command. By default, Cargo and `rustc`
use the libtest harness which is responsible for collecting functions
use the [libtest harness] which is responsible for collecting functions
annotated with the [`#[test]` attribute][test-attribute] and executing them in
parallel, reporting the success and failure of each test. See [the `harness`
field](#the-harness-field) if you want to use a different harness or test
strategy.
[libtest harness]: ../../rustc/tests/index.html
#### Integration tests
Files located under the [`tests` directory][package layout] are integration

View File

@ -21,14 +21,14 @@ system:
* `RUSTC` — Instead of running `rustc`, Cargo will execute this specified
compiler instead. See [`build.rustc`] to set via config.
* `RUSTC_WRAPPER` — Instead of simply running `rustc`, Cargo will execute this
specified wrapper instead, passing as its commandline arguments the rustc
specified wrapper instead, passing as its command-line arguments the rustc
invocation, with the first argument being `rustc`. Useful to set up a build
cache tool such as `sccache`. See [`build.rustc-wrapper`] to set via config.
* `RUSTC_WORKSPACE_WRAPPER` — Instead of simply running `rustc`, Cargo will
* `RUSTC_WORKSPACE_WRAPPER` — Instead of simply running `rustc`, Cargo will
execute this specified wrapper instead for workspace members only, passing
as its commandline arguments the rustc invocation, with the first argument
being `rustc`. It affects the filename hash so that artifacts produced by
the wrapper are cached separately. See [`build.rustc-workspace-wrapper`]
as its command-line arguments the rustc invocation, with the first argument
being `rustc`. It affects the filename hash so that artifacts produced by
the wrapper are cached separately. See [`build.rustc-workspace-wrapper`]
to set via config.
* `RUSTDOC` — Instead of running `rustdoc`, Cargo will execute this specified
`rustdoc` instance instead. See [`build.rustdoc`] to set via config.
@ -100,6 +100,7 @@ supported environment variables are:
* `CARGO_PROFILE_<name>_OPT_LEVEL` Set the optimization level, see [`profile.<name>.opt-level`].
* `CARGO_PROFILE_<name>_PANIC` The panic strategy to use, see [`profile.<name>.panic`].
* `CARGO_PROFILE_<name>_RPATH` The rpath linking option, see [`profile.<name>.rpath`].
* `CARGO_PROFILE_<name>_SPLIT_DEBUGINFO` Controls debug file output behavior, see [`profile.<name>.split-debuginfo`].
* `CARGO_REGISTRIES_<name>_INDEX` — URL of a registry index, see [`registries.<name>.index`].
* `CARGO_REGISTRIES_<name>_TOKEN` — Authentication token of a registry, see [`registries.<name>.token`].
* `CARGO_REGISTRY_DEFAULT` — Default registry for the `--registry` flag, see [`registry.default`].
@ -159,6 +160,7 @@ supported environment variables are:
[`profile.<name>.opt-level`]: config.md#profilenameopt-level
[`profile.<name>.panic`]: config.md#profilenamepanic
[`profile.<name>.rpath`]: config.md#profilenamerpath
[`profile.<name>.split-debuginfo`]: config.md#profilenamesplit-debuginfo
[`registries.<name>.index`]: config.md#registriesnameindex
[`registries.<name>.token`]: config.md#registriesnametoken
[`registry.default`]: config.md#registrydefault
@ -219,6 +221,12 @@ corresponding environment variable is set to the empty string, `""`.
on the current directory and the default workspace members. This environment
variable will not be set when building dependencies. This is only set when
compiling the package (not when running binaries or tests).
* `CARGO_TARGET_TMPDIR` — Only set when building [integration test] or benchmark code.
This is a path to a directory inside the target directory
where integration tests or benchmarks are free to put any data needed by
the tests/benches. Cargo initially creates this directory but doesn't
manage its content in any way, this is the responsibility of the test code.
There are separate directories for `debug` and `release` profiles.
[integration test]: cargo-targets.md#integration-tests
[`env` macro]: ../../std/macro.env.html
@ -308,7 +316,7 @@ let out_dir = env::var("OUT_DIR").unwrap();
* `TARGET` — the target triple that is being compiled for. Native code should be
compiled for this triple. See the [Target Triple] description
for more information.
* `HOST` — the host triple of the rust compiler.
* `HOST` — the host triple of the Rust compiler.
* `NUM_JOBS` — the parallelism specified as the top-level parallelism. This can
be useful to pass a `-j` parameter to a system like `make`. Note
that care should be taken when interpreting this environment

View File

@ -440,7 +440,7 @@ guide, consider adding the documentation there (for example, see [serde.rs]).
If you have a binary project, consider documenting the features in the README
or other documentation for the project (for example, see [sccache]).
Clearly documenting the features can set expectations about features
Clearly documenting the features can set expectations about features that are
considered "unstable" or otherwise shouldn't be used. For example, if there is
an optional dependency, but you don't want users to explicitly list that
optional dependency as a feature, exclude it from the documented list.

View File

@ -98,11 +98,11 @@ Versioning](https://semver.org/), so make sure you follow some basic rules:
See the [Resolver] chapter for more information on how Cargo uses versions to
resolve dependencies, and for guidelines on setting your own version. See the
[Semver compatibility] chapter for more details on exactly what constitutes a
[SemVer compatibility] chapter for more details on exactly what constitutes a
breaking change.
[Resolver]: resolver.md
[Semver compatibility]: semver.md
[SemVer compatibility]: semver.md
<a id="the-authors-field-optional"></a>
#### The `authors` field

View File

@ -222,7 +222,7 @@ Note that this will actually resolve to two versions of the `uuid` crate. The
`my-binary` crate will continue to use the 1.x.y series of the `uuid` crate but
the `my-library` crate will use the `2.0.0` version of `uuid`. This will allow you
to gradually roll out breaking changes to a crate through a dependency graph
without being force to update everything all at once.
without being forced to update everything all at once.
### Using `[patch]` with multiple versions

View File

@ -107,7 +107,7 @@ the crates that are present).
A "directory source" is similar to a local registry source where it contains a
number of crates available on the local filesystem, suitable for vendoring
dependencies. Directory sources are primarily managed the `cargo vendor`
dependencies. Directory sources are primarily managed by the `cargo vendor`
subcommand.
Directory sources are distinct from local registries though in that they contain

View File

@ -58,6 +58,55 @@ Each new feature described below should explain how to use it.
[nightly channel]: ../../book/appendix-07-nightly-rust.html
[stabilized]: https://doc.crates.io/contrib/process/unstable.html#stabilization
### List of unstable features
* Unstable-specific features
* [-Z allow-features](#allow-features) — Provides a way to restrict which unstable features are used.
* Build scripts and linking
* [extra-link-arg](#extra-link-arg) — Allows build scripts to pass extra link arguments in more cases.
* [Metabuild](#metabuild) — Provides declarative build scripts.
* Resolver and features
* [no-index-update](#no-index-update) — Prevents cargo from updating the index cache.
* [avoid-dev-deps](#avoid-dev-deps) — Prevents the resolver from including dev-dependencies during resolution.
* [minimal-versions](#minimal-versions) — Forces the resolver to use the lowest compatible version instead of the highest.
* [public-dependency](#public-dependency) — Allows dependencies to be classified as either public or private.
* [Namespaced features](#namespaced-features) — Separates optional dependencies into a separate namespace from regular features, and allows feature names to be the same as some dependency name.
* [Weak dependency features](#weak-dependency-features) — Allows setting features for dependencies without enabling optional dependencies.
* Output behavior
* [out-dir](#out-dir) — Adds a directory where artifacts are copied to.
* [terminal-width](#terminal-width) — Tells rustc the width of the terminal so that long diagnostic messages can be truncated to be more readable.
* Compile behavior
* [mtime-on-use](#mtime-on-use) — Updates the last-modified timestamp on every dependency every time it is used, to provide a mechanism to delete unused artifacts.
* [doctest-xcompile](#doctest-xcompile) — Supports running doctests with the `--target` flag.
* [multitarget](#multitarget) — Supports building for multiple targets at the same time.
* [build-std](#build-std) — Builds the standard library instead of using pre-built binaries.
* [build-std-features](#build-std-features) — Sets features to use with the standard library.
* [binary-dep-depinfo](#binary-dep-depinfo) — Causes the dep-info file to track binary dependencies.
* [panic-abort-tests](#panic-abort-tests) — Allows running tests with the "abort" panic strategy.
* rustdoc
* [`doctest-in-workspace`](#doctest-in-workspace) — Fixes workspace-relative paths when running doctests.
* [rustdoc-map](#rustdoc-map) — Provides mappings for documentation to link to external sites like [docs.rs](https://docs.rs/).
* `Cargo.toml` extensions
* [Custom named profiles](#custom-named-profiles) — Adds custom named profiles in addition to the standard names.
* [Profile `strip` option](#profile-strip-option) — Forces the removal of debug information and symbols from executables.
* [per-package-target](#per-package-target) — Sets the `--target` to use for each individual package.
* [rust-version](#rust-version) — Allows to declare the minimum supported Rust version.
* [Edition 2021](#edition-2021) — Adds support for the 2021 Edition.
* Information and metadata
* [Build-plan](#build-plan) — Emits JSON information on which commands will be run.
* [timings](#timings) — Generates a report on how long individual dependencies took to run.
* [unit-graph](#unit-graph) — Emits JSON for Cargo's internal graph structure.
* [future incompat report](#future-incompat-report) — Displays a report for future incompatibilities that may error in the future.
* Configuration
* [config-cli](#config-cli) — Adds the ability to pass configuration options on the command-line.
* [config-include](#config-include) — Adds the ability for config files to include other files.
* [configurable-env](#configurable-env) — Adds support for defining environment variables that will be set when building and running.
* [patch-in-config](#patch-in-config) — Adds support for specifying the `[patch]` table in config files.
* [`cargo config`](#cargo-config) — Adds a new subcommand for viewing config files.
* Registries
* [credential-process](#credential-process) — Adds support for fetching registry tokens from an external authentication program.
* [`cargo logout`](#cargo-logout) — Adds the `logout` command to remove the currently saved registry token.
### allow-features
This permanently-unstable flag makes it so that only a listed set of
@ -158,7 +207,7 @@ generated if dev-dependencies are skipped.
> versions for direct dependencies.
When a `Cargo.lock` file is generated, the `-Z minimal-versions` flag will
resolve the dependencies to the minimum semver version that will satisfy the
resolve the dependencies to the minimum SemVer version that will satisfy the
requirements (instead of the greatest version).
The intended use-case of this flag is to check, during continuous integration,
@ -798,7 +847,7 @@ Other possible string values of `strip` are `none`, `symbols`, and `off`. The de
You can also configure this option with the two absolute boolean values
`true` and `false`. The former enables `strip` at its higher level, `symbols`,
whilst the later disables `strip` completely.
while the latter disables `strip` completely.
### rustdoc-map
* Tracking Issue: [#8296](https://github.com/rust-lang/cargo/issues/8296)
@ -1104,7 +1153,7 @@ cargo logout -Z credential-process
* RFC: [#2495](https://github.com/rust-lang/rfcs/blob/master/text/2495-min-rust-version.md)
* rustc Tracking Issue: [#65262](https://github.com/rust-lang/rust/issues/65262)
The `-Z rust-version` flag enables the reading the `rust-version` field in the
The `-Z rust-version` flag enables the reading of the `rust-version` field in the
Cargo manifest `package` section. This can be used by a package to state a minimal
version of the compiler required to build the package. An error is generated if
the version of rustc is older than the stated `rust-version`. The
@ -1150,9 +1199,18 @@ The 2021 edition will set the default [resolver version] to "2".
* RFC: [#2834](https://github.com/rust-lang/rfcs/blob/master/text/2834-cargo-report-future-incompat.md)
* rustc Tracking Issue: [#71249](https://github.com/rust-lang/rust/issues/71249)
The `-Z future-incompat-report` flag enables the creation of a future-incompat report
for all dependencies. This makes users aware if any of their crate's dependencies
might stop compiling with a future version of Rust.
The `-Z future-incompat-report` flag causes Cargo to check for
future-incompatible warnings in all dependencies. These are warnings for
changes that may become hard errors in the future, causing the dependency to
stop building in a future version of rustc. If any warnings are found, a small
notice is displayed indicating that the warnings were found, and provides
instructions on how to display a full report.
A full report can be displayed with the `cargo report future-incompatibilities
-Z future-incompat-report --id ID` command, or by running the build again with
the `--future-incompat-report` flag. The developer should then update their
dependencies to a version where the issue is fixed, or work with the
developers of the dependencies to help resolve the issue.
### configurable-env
* Original Pull Request: [#9175](https://github.com/rust-lang/cargo/pull/9175)
@ -1205,7 +1263,7 @@ lowest precedence.
Relative `path` dependencies in such a `[patch]` section are resolved
relative to the configuration file they appear in.
## `cargo config`
### `cargo config`
* Original Issue: [#2362](https://github.com/rust-lang/cargo/issues/2362)
* Tracking Issue: [#9301](https://github.com/rust-lang/cargo/issues/9301)
@ -1239,6 +1297,20 @@ from the root of the workspace. It also passes the `--test-run-directory` to
package. This preserves backwards compatibility and is consistent with how
normal unittests are run.
### rustc `--print`
* Tracking Issue: [#9357](https://github.com/rust-lang/cargo/issues/9357)
`cargo rustc --print=VAL` forwards the `--print` flag to `rustc` in order to
extract information from `rustc`. This runs `rustc` with the corresponding
[`--print`](https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information)
flag, and then immediately exits without compiling. Exposing this as a cargo
flag allows cargo to inject the correct target and RUSTFLAGS based on the
current configuration.
The primary use case is to run `cargo rustc --print=cfg` to get config values
for the appropriate target and influenced by any other RUSTFLAGS.
<script>
(function() {
var fragments = {

View File

@ -15,9 +15,12 @@ the two dashes (\fB\-\-\fR) are passed to the benchmark binaries and thus to
\fIlibtest\fR (rustc's built in unit\-test and micro\-benchmarking framework). If
you are passing arguments to both Cargo and the binary, the ones after \fB\-\-\fR go
to the binary, the ones before go to Cargo. For details about libtest's
arguments see the output of \fBcargo bench \-\- \-\-help\fR\&. As an example, this will
run only the benchmark named \fBfoo\fR (and skip other similarly named benchmarks
like \fBfoobar\fR):
arguments see the output of \fBcargo bench \-\- \-\-help\fR and check out the rustc
book's chapter on how tests work at
<https://doc.rust\-lang.org/rustc/tests/index.html>\&.
.sp
As an example, this will run only the benchmark named \fBfoo\fR (and skip other
similarly named benchmarks like \fBfoobar\fR):
.sp
.RS 4
.nf

View File

@ -15,7 +15,8 @@ dashes (\fB\-\-\fR) are passed to the test binaries and thus to \fIlibtest\fR (r
built in unit\-test and micro\-benchmarking framework). If you're passing
arguments to both Cargo and the binary, the ones after \fB\-\-\fR go to the binary,
the ones before go to Cargo. For details about libtest's arguments see the
output of \fBcargo test \-\- \-\-help\fR\&.
output of \fBcargo test \-\- \-\-help\fR and check out the rustc book's chapter on
how tests work at <https://doc.rust\-lang.org/rustc/tests/index.html>\&.
.sp
As an example, this will filter for tests with \fBfoo\fR in their name and run them
on 3 threads in parallel:

View File

@ -1334,12 +1334,18 @@ fn crate_env_vars() {
let s = format!("{}.{}.{}-{}", VERSION_MAJOR,
VERSION_MINOR, VERSION_PATCH, VERSION_PRE);
assert_eq!(s, VERSION);
// Verify CARGO_TARGET_TMPDIR isn't set for bins
assert!(option_env!("CARGO_TARGET_TMPDIR").is_none());
}
"#,
)
.file(
"src/lib.rs",
r#"
use std::env;
use std::path::PathBuf;
pub fn version() -> String {
format!("{}-{}-{} @ {} in {}",
env!("CARGO_PKG_VERSION_MAJOR"),
@ -1348,9 +1354,60 @@ fn crate_env_vars() {
env!("CARGO_PKG_VERSION_PRE"),
env!("CARGO_MANIFEST_DIR"))
}
pub fn check_no_int_test_env() {
env::var("CARGO_TARGET_DIR").unwrap_err();
}
pub fn check_tmpdir(tmp: Option<&'static str>) {
let tmpdir: PathBuf = tmp.unwrap().into();
let exe: PathBuf = env::current_exe().unwrap().into();
let mut expected: PathBuf = exe.parent().unwrap().parent().unwrap().into();
expected.push("tmp");
assert_eq!(tmpdir, expected);
// Check that CARGO_TARGET_TMPDIR isn't set for lib code
assert!(option_env!("CARGO_TARGET_TMPDIR").is_none());
env::var("CARGO_TARGET_TMPDIR").unwrap_err();
}
#[test]
fn env() {
// Check that CARGO_TARGET_TMPDIR isn't set for unit tests
assert!(option_env!("CARGO_TARGET_TMPDIR").is_none());
env::var("CARGO_TARGET_TMPDIR").unwrap_err();
}
"#,
)
.build();
.file(
"tests/env.rs",
r#"
#[test]
fn env() {
foo::check_tmpdir(option_env!("CARGO_TARGET_TMPDIR"));
}
"#,
);
let p = if is_nightly() {
p.file(
"benches/env.rs",
r#"
#![feature(test)]
extern crate test;
use test::Bencher;
#[bench]
fn env(_: &mut Bencher) {
foo::check_tmpdir(option_env!("CARGO_TARGET_TMPDIR"));
}
"#,
)
.build()
} else {
p.build()
};
println!("build");
p.cargo("build -v").run();
@ -1362,6 +1419,11 @@ fn crate_env_vars() {
println!("test");
p.cargo("test -v").run();
if is_nightly() {
println!("bench");
p.cargo("bench -v").run();
}
}
#[cargo_test]

View File

@ -583,7 +583,7 @@ opt-level = 'foo'
error in [..]/.cargo/config: could not load config key `profile.dev.opt-level`
Caused by:
must be an integer, `z`, or `s`, but found the string: \"foo\"",
must be `0`, `1`, `2`, `3`, `s` or `z`, but found the string: \"foo\"",
);
let config = ConfigBuilder::new()
@ -596,7 +596,7 @@ Caused by:
error in environment variable `CARGO_PROFILE_DEV_OPT_LEVEL`: could not load config key `profile.dev.opt-level`
Caused by:
must be an integer, `z`, or `s`, but found the string: \"asdf\"",
must be `0`, `1`, `2`, `3`, `s` or `z`, but found the string: \"asdf\"",
);
}

View File

@ -43,10 +43,8 @@ fn gate_future_incompat_report() {
.with_status(101)
.run();
p.cargo("describe-future-incompatibilities --id foo")
.with_stderr_contains(
"error: `cargo describe-future-incompatibilities` can only be used on the nightly channel"
)
p.cargo("report future-incompatibilities --id foo")
.with_stderr_contains("error: `cargo report` can only be used on the nightly channel")
.with_status(101)
.run();
}
@ -134,7 +132,7 @@ fn test_multi_crate() {
.with_stderr_does_not_contain("[..]triggers[..]")
.run();
p.cargo("describe-future-incompatibilities -Z future-incompat-report --id bad-id")
p.cargo("report future-incompatibilities -Z future-incompat-report --id bad-id")
.masquerade_as_nightly_cargo()
.with_stderr_contains("error: Expected an id of [..]")
.with_stderr_does_not_contain("[..]triggers[..]")
@ -157,7 +155,7 @@ fn test_multi_crate() {
.unwrap();
// Extract the 'id' from the stdout. We are looking
// for the id in a line of the form "run `cargo describe-future-incompatibilities --id yZ7S`"
// for the id in a line of the form "run `cargo report future-incompatibilities --id yZ7S`"
// which is generated by Cargo to tell the user what command to run
// This is just to test that passing the id suppresses the warning mesasge. Any users needing
// access to the report from a shell script should use the `--future-incompat-report` flag
@ -172,7 +170,7 @@ fn test_multi_crate() {
// Strip off the trailing '`' included in the output
let id: String = id.chars().take_while(|c| *c != '`').collect();
p.cargo(&format!("describe-future-incompatibilities -Z future-incompat-report --id {}", id))
p.cargo(&format!("report future-incompatibilities -Z future-incompat-report --id {}", id))
.masquerade_as_nightly_cargo()
.with_stderr_contains("The crate `first-dep v0.0.1` currently triggers the following future incompatibility lints:")
.with_stderr_contains("The crate `second-dep v0.0.2` currently triggers the following future incompatibility lints:")

View File

@ -2760,7 +2760,7 @@ to proceed despite [..]
git::commit(&repo);
git_project.cargo("package --no-verify").run();
// Modify within nested submodule.
git_project.change_file("src/bar/mod.rs", "//test");
git_project.change_file("src/bar/new_file.rs", "//test");
git_project
.cargo("package --no-verify")
.with_status(101)
@ -2770,7 +2770,7 @@ to proceed despite [..]
See [..]
[ERROR] 1 files in the working directory contain changes that were not yet committed into git:
src/bar/mod.rs
src/bar/new_file.rs
to proceed despite [..]
",

View File

@ -5,7 +5,7 @@ use std::io::prelude::*;
use cargo_test_support::cross_compile;
use cargo_test_support::git;
use cargo_test_support::registry::{registry_path, registry_url, Package};
use cargo_test_support::registry::{self, registry_path, registry_url, Package};
use cargo_test_support::{
basic_manifest, cargo_process, no_such_file_err_msg, project, symlink_supported, t,
};
@ -13,7 +13,7 @@ use cargo_test_support::{
use cargo_test_support::install::{
assert_has_installed_exe, assert_has_not_installed_exe, cargo_home,
};
use cargo_test_support::paths;
use cargo_test_support::paths::{self, CargoPathExt};
use std::env;
use std::path::PathBuf;
@ -1739,3 +1739,60 @@ fn locked_install_without_published_lockfile() {
.with_stderr_contains("[WARNING] no Cargo.lock file published in foo v0.1.0")
.run();
}
#[cargo_test]
fn install_semver_metadata() {
// Check trying to install a package that uses semver metadata.
// This uses alt registry because the bug this is exercising doesn't
// trigger with a replaced source.
registry::alt_init();
Package::new("foo", "1.0.0+abc")
.alternative(true)
.file("src/main.rs", "fn main() {}")
.publish();
cargo_process("install foo --registry alternative --version 1.0.0+abc").run();
cargo_process("install foo --registry alternative")
.with_stderr("\
[UPDATING] `[ROOT]/alternative-registry` index
[IGNORED] package `foo v1.0.0+abc (registry `[ROOT]/alternative-registry`)` is already installed, use --force to override
[WARNING] be sure to add [..]
")
.run();
// "Updating" is not displayed here due to the --version fast-path.
cargo_process("install foo --registry alternative --version 1.0.0+abc")
.with_stderr("\
[IGNORED] package `foo v1.0.0+abc (registry `[ROOT]/alternative-registry`)` is already installed, use --force to override
[WARNING] be sure to add [..]
")
.run();
cargo_process("install foo --registry alternative --version 1.0.0 --force")
.with_stderr(
"\
[UPDATING] `[ROOT]/alternative-registry` index
[INSTALLING] foo v1.0.0+abc (registry `[ROOT]/alternative-registry`)
[COMPILING] foo v1.0.0+abc (registry `[ROOT]/alternative-registry`)
[FINISHED] [..]
[REPLACING] [ROOT]/home/.cargo/bin/foo[EXE]
[REPLACED] package [..]
[WARNING] be sure to add [..]
",
)
.run();
// Check that from a fresh cache will work without metadata, too.
paths::home().join(".cargo/registry").rm_rf();
paths::home().join(".cargo/bin").rm_rf();
cargo_process("install foo --registry alternative --version 1.0.0")
.with_stderr("\
[UPDATING] `[ROOT]/alternative-registry` index
[DOWNLOADING] crates ...
[DOWNLOADED] foo v1.0.0+abc (registry `[ROOT]/alternative-registry`)
[INSTALLING] foo v1.0.0+abc (registry `[ROOT]/alternative-registry`)
[COMPILING] foo v1.0.0+abc (registry `[ROOT]/alternative-registry`)
[FINISHED] [..]
[INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE]
[INSTALLED] package `foo v1.0.0+abc (registry `[ROOT]/alternative-registry`)` (executable `foo[EXE]`)
[WARNING] be sure to add [..]
")
.run();
}

View File

@ -816,6 +816,59 @@ to proceed despite this and include the uncommitted changes, pass the `--allow-d
.run();
}
#[cargo_test]
fn dirty_ignored() {
// Cargo warns about an ignored file that will be published.
let (p, repo) = git::new_repo("foo", |p| {
p.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
description = "foo"
license = "foo"
documentation = "foo"
include = ["src", "build"]
"#,
)
.file("src/lib.rs", "")
.file(".gitignore", "build")
});
// Example of adding a file that is confusingly ignored by an overzealous
// gitignore rule.
p.change_file("src/build/mod.rs", "");
p.cargo("package --list")
.with_status(101)
.with_stderr(
"\
error: 1 files in the working directory contain changes that were not yet committed into git:
src/build/mod.rs
to proceed despite this and include the uncommitted changes, pass the `--allow-dirty` flag
",
)
.run();
// Add the ignored file and make sure it is included.
let mut index = t!(repo.index());
t!(index.add_path(Path::new("src/build/mod.rs")));
t!(index.write());
git::commit(&repo);
p.cargo("package --list")
.with_stderr("")
.with_stdout(
"\
.cargo_vcs_info.json
Cargo.toml
Cargo.toml.orig
src/build/mod.rs
src/lib.rs
",
)
.run();
}
#[cargo_test]
fn generated_manifest() {
registry::alt_init();

View File

@ -50,6 +50,50 @@ fn add_vendor_config(p: &Project) {
);
}
#[cargo_test]
fn package_exclude() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
[dependencies]
bar = "0.1.0"
"#,
)
.file("src/lib.rs", "")
.build();
Package::new("bar", "0.1.0")
.file(
"Cargo.toml",
r#"
[package]
name = "bar"
version = "0.1.0"
exclude = [".*", "!.include", "!.dotdir/include"]
"#,
)
.file("src/lib.rs", "")
.file(".exclude", "")
.file(".include", "")
.file(".dotdir/exclude", "")
.file(".dotdir/include", "")
.publish();
p.cargo("vendor --respect-source-config").run();
let csum = dbg!(p.read_file("vendor/bar/.cargo-checksum.json"));
assert!(csum.contains(".include"));
assert!(!csum.contains(".exclude"));
assert!(!csum.contains(".dotdir/exclude"));
// Gitignore doesn't re-include a file in an excluded parent directory,
// even if negating it explicitly.
assert!(!csum.contains(".dotdir/include"));
}
#[cargo_test]
fn two_versions() {
let p = project()