mirror of
https://github.com/rust-lang/cargo.git
synced 2025-10-01 11:30:39 +00:00
Merge branch 'master' of github.com:rust-lang/cargo into unknown-feature-resolver-1
This commit is contained in:
commit
766c3bbcb8
4
.github/workflows/main.yml
vendored
4
.github/workflows/main.yml
vendored
@ -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
|
||||
|
70
CHANGELOG.md
70
CHANGELOG.md
@ -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)
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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));
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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<()> {
|
||||
|
15
crates/mdman/Cargo.lock
generated
15
crates/mdman/Cargo.lock
generated
@ -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",
|
||||
|
@ -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"
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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,
|
@ -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)?;
|
||||
|
@ -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)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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(|| {
|
||||
|
@ -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(())
|
||||
|
@ -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()
|
||||
});
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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>> {
|
||||
|
@ -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.
|
||||
|
@ -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
67
src/cargo/util/counter.rs
Normal 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());
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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<()> {
|
||||
|
@ -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
|
||||
);
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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).
|
||||
|
@ -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
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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.
|
||||
|
@ -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)'
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 = {
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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]
|
||||
|
@ -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\"",
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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:")
|
||||
|
@ -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 [..]
|
||||
",
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user