diff -Nru cargo-0.54.0/build.rs cargo-0.58.0/build.rs --- cargo-0.54.0/build.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/build.rs 2021-10-21 14:30:11.000000000 +0000 @@ -5,6 +5,10 @@ fn main() { compress_man(); + println!( + "cargo:rustc-env=RUST_HOST_TARGET={}", + std::env::var("TARGET").unwrap() + ); } fn compress_man() { diff -Nru cargo-0.54.0/Cargo.toml cargo-0.58.0/Cargo.toml --- cargo-0.54.0/Cargo.toml 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/Cargo.toml 2021-10-21 14:30:11.000000000 +0000 @@ -1,6 +1,6 @@ [package] name = "cargo" -version = "0.54.0" +version = "0.58.0" edition = "2018" authors = ["Yehuda Katz ", "Carl Lerche ", @@ -21,18 +21,18 @@ [dependencies] atty = "0.2" bytesize = "1.0" -cargo-platform = { path = "crates/cargo-platform", version = "0.1.1" } -cargo-util = { path = "crates/cargo-util", version = "0.1.0" } +cargo-platform = { path = "crates/cargo-platform", version = "0.1.2" } +cargo-util = { path = "crates/cargo-util", version = "0.1.1" } crates-io = { path = "crates/crates-io", version = "0.33.0" } crossbeam-utils = "0.8" -curl = { version = "0.4.23", features = ["http2"] } -curl-sys = "0.4.22" -env_logger = "0.8.1" +curl = { version = "0.4.39", features = ["http2"] } +curl-sys = "0.4.49" +env_logger = "0.9.0" pretty_env_logger = { version = "0.4", optional = true } anyhow = "1.0" filetime = "0.2.9" flate2 = { version = "1.0.3", default-features = false, features = ["zlib"] } -git2 = "0.13.16" +git2 = "0.13.23" git2-curl = "0.14.1" glob = "0.3.0" hex = "0.4" @@ -40,39 +40,40 @@ humantime = "2.0.0" ignore = "0.4.7" lazy_static = "1.2.0" -jobserver = "0.1.21" +jobserver = "0.1.24" lazycell = "1.2.0" libc = "0.2" log = "0.4.6" -libgit2-sys = "0.12.18" +libgit2-sys = "0.12.24" memchr = "2.1.3" num_cpus = "1.0" -opener = "0.4" +opener = "0.5" +os_info = "3.0.7" percent-encoding = "2.0" -rustfix = "0.5.0" -semver = { version = "0.10", features = ["serde"] } +rustfix = "0.6.0" +semver = { version = "1.0.3", features = ["serde"] } serde = { version = "1.0.123", features = ["derive"] } serde_ignored = "0.1.0" serde_json = { version = "1.0.30", features = ["raw_value"] } shell-escape = "0.1.4" strip-ansi-escapes = "0.1.0" -tar = { version = "0.4.26", default-features = false } +tar = { version = "0.4.35", default-features = false } 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" openssl = { version = '0.10.11', optional = true } im-rc = "15.0.0" +itertools = "0.10.0" # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` # for more information. rustc-workspace-hack = "1.0.0" -rand = "0.8.3" [target.'cfg(windows)'.dependencies] fwdansi = "1.1.0" diff -Nru cargo-0.54.0/CHANGELOG.md cargo-0.58.0/CHANGELOG.md --- cargo-0.54.0/CHANGELOG.md 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/CHANGELOG.md 2021-10-21 14:30:11.000000000 +0000 @@ -1,17 +1,333 @@ # Changelog -## Cargo 1.53 (2021-06-17) -[90691f2b...HEAD](https://github.com/rust-lang/cargo/compare/90691f2b...HEAD) +## Cargo 1.57 (2021-12-02) +[18751dd3...HEAD](https://github.com/rust-lang/cargo/compare/18751dd3...HEAD) + +### Added + +- The `rev` option for a git dependency now supports git references that start + with `refs/`. An example where this can be used is to depend on a pull + request from a service like GitHub before it is merged. + [#9859](https://github.com/rust-lang/cargo/pull/9859) + +### Changed + +### Fixed + +- Removed a log message (from `CARGO_LOG`) that may leak tokens. + [#9873](https://github.com/rust-lang/cargo/pull/9873) + +### Nightly only + + +## Cargo 1.56 (2021-10-21) +[cebef295...rust-1.56.0](https://github.com/rust-lang/cargo/compare/cebef295...rust-1.56.0) + +### Added + +- 🎉 Cargo now supports the 2021 edition. + More information may be found in the [edition + guide](https://doc.rust-lang.org/nightly/edition-guide/rust-2021/index.html). + [#9800](https://github.com/rust-lang/cargo/pull/9800) +- 🎉 Added the + [`rust-version`](https://doc.rust-lang.org/nightly/cargo/reference/manifest.html#the-rust-version-field) + field to `Cargo.toml` to specify the minimum supported Rust version, and the + `--ignore-rust-version` command line option to override it. + [#9732](https://github.com/rust-lang/cargo/pull/9732) +- Added the `[env]` table to config files to specify environment variables to + set. + [docs](https://doc.rust-lang.org/nightly/cargo/reference/config.html#env) + [#9411](https://github.com/rust-lang/cargo/pull/9411) +- `[patch]` tables may now be specified in config files. + [docs](https://doc.rust-lang.org/nightly/cargo/reference/config.html#patch) + [#9839](https://github.com/rust-lang/cargo/pull/9839) +- `cargo doc` now supports the `--example` and `--examples` flags. + [#9808](https://github.com/rust-lang/cargo/pull/9808) +- 🎉 Build scripts can now pass additional linker arguments for binaries or all + linkable targets. [docs](https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#outputs-of-the-build-script) + [#9557](https://github.com/rust-lang/cargo/pull/9557) +- Added support for the `-p` flag for `cargo publish` to publish a specific + package in a workspace. `cargo package` also now supports `-p` and + `--workspace`. + [#9559](https://github.com/rust-lang/cargo/pull/9559) +- Added documentation about third-party registries. + [#9830](https://github.com/rust-lang/cargo/pull/9830) +- Added the `{sha256-checksum}` placeholder for URLs in a registry `config.json`. + [docs](https://doc.rust-lang.org/nightly/cargo/reference/registries.html#index-format) + [#9801](https://github.com/rust-lang/cargo/pull/9801) +- Added a warning when a dependency does not have a library. + [#9771](https://github.com/rust-lang/cargo/pull/9771) + +### Changed + +- Doc tests now support the `-q` flag to show terse test output. + [#9730](https://github.com/rust-lang/cargo/pull/9730) +- `features` used in a `[replace]` table now issues a warning, as they are ignored. + [#9681](https://github.com/rust-lang/cargo/pull/9681) +- Changed so that only `wasm32-unknown-emscripten` executables are built + without a hash in the filename. Previously it was all `wasm32` targets. + Additionally, all `apple` binaries are now built with a hash in the + filename. This allows multiple copies to be cached at once, and matches the + behavior on other platforms (except `msvc`). + [#9653](https://github.com/rust-lang/cargo/pull/9653) +- `cargo new` now generates an example that doesn't generate a warning with + clippy. + [#9796](https://github.com/rust-lang/cargo/pull/9796) +- `cargo fix --edition` now only applies edition-specific lints. + [#9846](https://github.com/rust-lang/cargo/pull/9846) +- Improve resolver message to include dependency requirements. + [#9827](https://github.com/rust-lang/cargo/pull/9827) +- `cargo fix` now has more debug logging available with the `CARGO_LOG` + environment variable. + [#9831](https://github.com/rust-lang/cargo/pull/9831) +- Changed `cargo fix --edition` to emit a warning when on the latest stable + edition when running on stable instead of generating an error. + [#9792](https://github.com/rust-lang/cargo/pull/9792) +- `cargo install` will now determine all of the packages to install before + starting the installation, which should help with reporting errors without + partially installing. + [#9793](https://github.com/rust-lang/cargo/pull/9793) +- The resolver report for `cargo fix --edition` now includes differences for + dev-dependencies. + [#9803](https://github.com/rust-lang/cargo/pull/9803) +- `cargo fix` will now show better diagnostics for abnormal errors from `rustc`. + [#9799](https://github.com/rust-lang/cargo/pull/9799) +- Entries in `cargo --list` are now deduplicated. + [#9773](https://github.com/rust-lang/cargo/pull/9773) +- Aliases are now included in `cargo --list`. + [#9764](https://github.com/rust-lang/cargo/pull/9764) + +### Fixed + +- Fixed panic with build-std of a proc-macro. + [#9834](https://github.com/rust-lang/cargo/pull/9834) +- Fixed running `cargo` recursively from proc-macros while running `cargo fix`. + [#9818](https://github.com/rust-lang/cargo/pull/9818) +- Return an error instead of a stack overflow for command alias loops. + [#9791](https://github.com/rust-lang/cargo/pull/9791) + +### Nightly only + +- Added `[future-incompat-report]` config section. + [#9774](https://github.com/rust-lang/cargo/pull/9774) +- Fixed value-after-table error with custom named profiles. + [#9789](https://github.com/rust-lang/cargo/pull/9789) +- Added the `different-binary-name` feature to support specifying a + non-rust-identifier for a binary name. + [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#different-binary-name) + [#9627](https://github.com/rust-lang/cargo/pull/9627) +- Added a profile option to select the codegen backend. + [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#codegen-backend) + [#9118](https://github.com/rust-lang/cargo/pull/9118) + + +## Cargo 1.55 (2021-09-09) +[aa8b0929...rust-1.55.0](https://github.com/rust-lang/cargo/compare/aa8b0929...rust-1.55.0) ### Added +- The package definition in `cargo metadata` now includes the `"default_run"` + field from the manifest. + [#9550](https://github.com/rust-lang/cargo/pull/9550) +- Build scripts now have access to the following environment variables: + `RUSTC_WRAPPER`, `RUSTC_WORKSPACE_WRAPPER`, `CARGO_ENCODED_RUSTFLAGS`. + [docs](https://doc.rust-lang.org/nightly/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts) + [#9601](https://github.com/rust-lang/cargo/pull/9601) +- Added `cargo d` as an alias for `cargo doc`. + [#9680](https://github.com/rust-lang/cargo/pull/9680) +- Added `{lib}` to the `cargo tree --format` option to display the library + name of a package. + [#9663](https://github.com/rust-lang/cargo/pull/9663) +- Added `members_mut` method to the `Workspace` API. + [#9547](https://github.com/rust-lang/cargo/pull/9547) + +### Changed + +- If a build command does not match any targets when using the + `--all-targets`, `--bins`, `--tests`, `--examples`, or `--benches` flags, a + warning is now displayed to inform you that there were no matching targets. + [#9549](https://github.com/rust-lang/cargo/pull/9549) +- The way `cargo init` detects whether or not existing source files represent + a binary or library has been changed to respect the command-line flags + instead of trying to guess which type it is. + [#9522](https://github.com/rust-lang/cargo/pull/9522) +- Registry names are now displayed instead of registry URLs when possible. + [#9632](https://github.com/rust-lang/cargo/pull/9632) +- Duplicate compiler diagnostics are no longer shown. This can often happen + with `cargo test` which builds multiple copies of the same code in parallel. + This also updates the warning summary to provide more context. + [#9675](https://github.com/rust-lang/cargo/pull/9675) +- The output for warnings or errors is now improved to be leaner, cleaner, and + show more context. + [#9655](https://github.com/rust-lang/cargo/pull/9655) +- Network send errors are now treated as "spurious" which means they will be retried. + [#9695](https://github.com/rust-lang/cargo/pull/9695) +- Git keys (`branch`, `tag`, `rev`) on a non-git dependency are now an error. + Additionally, specifying both `git` and `path` is now an error. + [#9689](https://github.com/rust-lang/cargo/pull/9689) +- Specifying a dependency without any keys is now an error. + [#9686](https://github.com/rust-lang/cargo/pull/9686) +- The resolver now prefers to use `[patch]` table entries of dependencies when + possible. + [#9639](https://github.com/rust-lang/cargo/pull/9639) +- Package name typo errors in dependencies are now displayed aligned with the + original to help make it easier to see the difference. + [#9665](https://github.com/rust-lang/cargo/pull/9665) +- Windows platforms may now warn on environment variables that have the wrong case. + [#9654](https://github.com/rust-lang/cargo/pull/9654) +- `features` used in a `[patch]` table now issues a warning, as they are ignored. + [#9666](https://github.com/rust-lang/cargo/pull/9666) +- The `target` directory is now excluded from content indexing on Windows. + [#9635](https://github.com/rust-lang/cargo/pull/9635) +- When `Cargo.toml` is not found, the error message now detects if it was + misnamed with a lowercase `c` to suggest the correct form. + [#9607](https://github.com/rust-lang/cargo/pull/9607) +- Building `diesel` with the new resolver displays a compatibility notice. + [#9602](https://github.com/rust-lang/cargo/pull/9602) +- Updated the `opener` dependency, which handles opening a web browser, which + includes several changes, such as new behavior when run on WSL, and using + the system `xdg-open` on Linux. + [#9583](https://github.com/rust-lang/cargo/pull/9583) +- Updated to libcurl 7.78. + [#9809](https://github.com/rust-lang/cargo/pull/9809) + [#9810](https://github.com/rust-lang/cargo/pull/9810) + +### Fixed + +- Fixed dep-info files including non-local build script paths. + [#9596](https://github.com/rust-lang/cargo/pull/9596) +- Handle "jobs = 0" case in cargo config files + [#9584](https://github.com/rust-lang/cargo/pull/9584) +- Implement warning for ignored trailing arguments after `--` + [#9561](https://github.com/rust-lang/cargo/pull/9561) +- Fixed rustc/rustdoc config values to be config-relative. + [#9566](https://github.com/rust-lang/cargo/pull/9566) +- `cargo fix` now supports rustc's suggestions with multiple spans. + [#9567](https://github.com/rust-lang/cargo/pull/9567) +- `cargo fix` now fixes each target serially instead of in parallel to avoid + problems with fixing the same file concurrently. + [#9677](https://github.com/rust-lang/cargo/pull/9677) +- Changes to the target `linker` config value now trigger a rebuild. + [#9647](https://github.com/rust-lang/cargo/pull/9647) +- Git unstaged deleted files are now ignored when using the `--allow-dirty` + flag with `cargo publish` or `cargo package`. + [#9645](https://github.com/rust-lang/cargo/pull/9645) + +### Nightly only + +- Enabled support for `cargo fix --edition` for 2021. + [#9588](https://github.com/rust-lang/cargo/pull/9588) +- Several changes to named profiles. + [#9685](https://github.com/rust-lang/cargo/pull/9685) +- Extended instructions on what to do when running `cargo fix --edition` on + the 2021 edition. + [#9694](https://github.com/rust-lang/cargo/pull/9694) +- Multiple updates to error messages using nightly features to help better + explain the situation. + [#9657](https://github.com/rust-lang/cargo/pull/9657) +- Adjusted the edition 2021 resolver diff report. + [#9649](https://github.com/rust-lang/cargo/pull/9649) +- Fixed error using `cargo doc --open` with `doc.extern-map`. + [#9531](https://github.com/rust-lang/cargo/pull/9531) +- Unified weak and namespaced features. + [#9574](https://github.com/rust-lang/cargo/pull/9574) +- Various updates to future-incompatible reporting. + [#9606](https://github.com/rust-lang/cargo/pull/9606) +- `[env]` environment variables are not allowed to set vars set by Cargo. + [#9579](https://github.com/rust-lang/cargo/pull/9579) + +## Cargo 1.54 (2021-07-29) +[4369396c...rust-1.54.0](https://github.com/rust-lang/cargo/compare/4369396c...rust-1.54.0) + +### 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) +- Added `--prune` option for `cargo tree` to limit what is displayed. + [#9520](https://github.com/rust-lang/cargo/pull/9520) +- Added `--depth` option for `cargo tree` to limit what is displayed. + [#9499](https://github.com/rust-lang/cargo/pull/9499) +- Added `cargo tree -e no-proc-macro` to hide procedural macro dependencies. + [#9488](https://github.com/rust-lang/cargo/pull/9488) +- Added `doc.browser` config option to set which browser to open with `cargo doc --open`. + [#9473](https://github.com/rust-lang/cargo/pull/9473) +- Added `CARGO_TARGET_TMPDIR` environment variable set for integration tests & + benches. This provides a temporary or "scratch" directory in the `target` + directory for tests and benches to use. + [#9375](https://github.com/rust-lang/cargo/pull/9375) + ### Changed +- `--features` CLI flags now provide typo suggestions with the new feature resolver. + [#9420](https://github.com/rust-lang/cargo/pull/9420) +- Cargo now uses a new parser for SemVer versions. This should behave mostly + the same as before with some minor exceptions where invalid syntax for + version requirements is now rejected. + [#9508](https://github.com/rust-lang/cargo/pull/9508) +- Mtime handling of `.crate` published packages has changed slightly to avoid + mtime values of 0. This was causing problems with lldb which refused to read + those files. + [#9517](https://github.com/rust-lang/cargo/pull/9517) +- Improved performance of git status check in `cargo package`. + [#9478](https://github.com/rust-lang/cargo/pull/9478) +- `cargo new` with fossil now places the ignore settings in the new repository + instead of using `fossil settings` to set them globally. This also includes + several other cleanups to make it more consistent with other VCS + configurations. + [#9469](https://github.com/rust-lang/cargo/pull/9469) +- `rustc-cdylib-link-arg` applying transitively displays a warning that this + was not intended, and may be an error in the future. + [#9563](https://github.com/rust-lang/cargo/pull/9563) + +### 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) +- Fixed a bug when with resolver = "1" non-virtual package was allowing + unknown features. + [#9437](https://github.com/rust-lang/cargo/pull/9437) +- Fixed an issue with the index cache mishandling versions that only + differed in build metadata (such as `110.0.0` and `110.0.0+1.1.0f`). + [#9476](https://github.com/rust-lang/cargo/pull/9476) +- Fixed `cargo install` with a semver metadata version. + [#9467](https://github.com/rust-lang/cargo/pull/9467) + +### 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) +- Added a `[host]` table to the config files to be able to set build flags for + host target. Also added `target-applies-to-host` to control how the + `[target]` tables behave. + [#9322](https://github.com/rust-lang/cargo/pull/9322) +- Added some validation to build script `rustc-link-arg-*` instructions to + return an error if the target doesn't exist. + [#9523](https://github.com/rust-lang/cargo/pull/9523) +- Added `cargo:rustc-link-arg-bin` instruction for build scripts. + [#9486](https://github.com/rust-lang/cargo/pull/9486) + + +## Cargo 1.53 (2021-06-17) +[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 +338,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 +368,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) diff -Nru cargo-0.54.0/ci/fetch-smoke-test.sh cargo-0.58.0/ci/fetch-smoke-test.sh --- cargo-0.54.0/ci/fetch-smoke-test.sh 1970-01-01 00:00:00.000000000 +0000 +++ cargo-0.58.0/ci/fetch-smoke-test.sh 2021-10-21 14:30:11.000000000 +0000 @@ -0,0 +1,27 @@ +#!/bin/bash +# This script builds with static curl, and verifies that fetching works. + +set -ex + +if [[ -z "$RUNNER_TEMP" ]] +then + echo "RUNNER_TEMP must be set" + exit 1 +fi + +if [ ! -f Cargo.toml ]; then + echo "Must be run from root of project." + exit 1 +fi + + +# Building openssl on Windows is a pain. +if [[ $(rustc -Vv | grep host:) != *windows* ]]; then + FEATURES='vendored-openssl,curl-sys/static-curl,curl-sys/force-system-lib-on-osx' + export LIBZ_SYS_STATIC=1 +fi + +cargo build --features "$FEATURES" +export CARGO_HOME=$RUNNER_TEMP/chome +target/debug/cargo fetch +rm -rf $CARGO_HOME diff -Nru cargo-0.54.0/crates/cargo-platform/Cargo.toml cargo-0.58.0/crates/cargo-platform/Cargo.toml --- cargo-0.54.0/crates/cargo-platform/Cargo.toml 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/crates/cargo-platform/Cargo.toml 2021-10-21 14:30:11.000000000 +0000 @@ -1,6 +1,6 @@ [package] name = "cargo-platform" -version = "0.1.1" +version = "0.1.2" authors = ["The Cargo Project Developers"] edition = "2018" license = "MIT OR Apache-2.0" diff -Nru cargo-0.54.0/crates/cargo-test-macro/src/lib.rs cargo-0.58.0/crates/cargo-test-macro/src/lib.rs --- cargo-0.54.0/crates/cargo-test-macro/src/lib.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/crates/cargo-test-macro/src/lib.rs 2021-10-21 14:30:11.000000000 +0000 @@ -31,8 +31,12 @@ } }; - 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 diff -Nru cargo-0.54.0/crates/cargo-test-support/Cargo.toml cargo-0.58.0/crates/cargo-test-support/Cargo.toml --- cargo-0.54.0/crates/cargo-test-support/Cargo.toml 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/crates/cargo-test-support/Cargo.toml 2021-10-21 14:30:11.000000000 +0000 @@ -16,9 +16,11 @@ flate2 = { version = "1.0", default-features = false, features = ["zlib"] } git2 = "0.13.16" glob = "0.3" +itertools = "0.10.0" lazy_static = "1.0" remove_dir_all = "0.5" serde_json = "1.0" tar = { version = "0.4.18", default-features = false } +termcolor = "1.1.2" toml = "0.5.7" -url = "2.0" +url = "2.2.2" diff -Nru cargo-0.54.0/crates/cargo-test-support/src/compare.rs cargo-0.58.0/crates/cargo-test-support/src/compare.rs --- cargo-0.54.0/crates/cargo-test-support/src/compare.rs 1970-01-01 00:00:00.000000000 +0000 +++ cargo-0.58.0/crates/cargo-test-support/src/compare.rs 2021-10-21 14:30:11.000000000 +0000 @@ -0,0 +1,583 @@ +//! Routines for comparing and diffing output. +//! +//! # Patterns +//! +//! Many of these functions support special markup to assist with comparing +//! text that may vary or is otherwise uninteresting for the test at hand. The +//! supported patterns are: +//! +//! - `[..]` is a wildcard that matches 0 or more characters on the same line +//! (similar to `.*` in a regex). It is non-greedy. +//! - `[EXE]` optionally adds `.exe` on Windows (empty string on other +//! platforms). +//! - `[ROOT]` is the path to the test directory's root. +//! - `[CWD]` is the working directory of the process that was run. +//! - There is a wide range of substitutions (such as `[COMPILING]` or +//! `[WARNING]`) to match cargo's "status" output and allows you to ignore +//! the alignment. See the source of `substitute_macros` for a complete list +//! of substitutions. +//! +//! # Normalization +//! +//! In addition to the patterns described above, the strings are normalized +//! in such a way to avoid unwanted differences. The normalizations are: +//! +//! - Raw tab characters are converted to the string ``. This is helpful +//! so that raw tabs do not need to be written in the expected string, and +//! to avoid confusion of tabs vs spaces. +//! - Backslashes are converted to forward slashes to deal with Windows paths. +//! This helps so that all tests can be written assuming forward slashes. +//! Other heuristics are applied to try to ensure Windows-style paths aren't +//! a problem. +//! - Carriage returns are removed, which can help when running on Windows. + +use crate::diff; +use crate::paths; +use anyhow::{bail, Context, Result}; +use serde_json::Value; +use std::env; +use std::fmt; +use std::path::Path; +use std::str; +use url::Url; + +/// Normalizes the output so that it can be compared against the expected value. +fn normalize_actual(actual: &str, cwd: Option<&Path>) -> String { + // It's easier to read tabs in outputs if they don't show up as literal + // hidden characters + let actual = actual.replace('\t', ""); + if cfg!(windows) { + // Let's not deal with \r\n vs \n on windows... + let actual = actual.replace('\r', ""); + normalize_windows(&actual, cwd) + } else { + actual + } +} + +/// Normalizes the expected string so that it can be compared against the actual output. +fn normalize_expected(expected: &str, cwd: Option<&Path>) -> String { + let expected = substitute_macros(expected); + if cfg!(windows) { + normalize_windows(&expected, cwd) + } else { + let expected = match cwd { + None => expected, + Some(cwd) => expected.replace("[CWD]", &cwd.display().to_string()), + }; + let expected = expected.replace("[ROOT]", &paths::root().display().to_string()); + expected + } +} + +/// Normalizes text for both actual and expected strings on Windows. +fn normalize_windows(text: &str, cwd: Option<&Path>) -> String { + // Let's not deal with / vs \ (windows...) + let text = text.replace('\\', "/"); + + // Weirdness for paths on Windows extends beyond `/` vs `\` apparently. + // Namely paths like `c:\` and `C:\` are equivalent and that can cause + // issues. The return value of `env::current_dir()` may return a + // lowercase drive name, but we round-trip a lot of values through `Url` + // which will auto-uppercase the drive name. To just ignore this + // distinction we try to canonicalize as much as possible, taking all + // forms of a path and canonicalizing them to one. + let replace_path = |s: &str, path: &Path, with: &str| { + let path_through_url = Url::from_file_path(path).unwrap().to_file_path().unwrap(); + let path1 = path.display().to_string().replace('\\', "/"); + let path2 = path_through_url.display().to_string().replace('\\', "/"); + s.replace(&path1, with) + .replace(&path2, with) + .replace(with, &path1) + }; + + let text = match cwd { + None => text, + Some(p) => replace_path(&text, p, "[CWD]"), + }; + + // Similar to cwd above, perform similar treatment to the root path + // which in theory all of our paths should otherwise get rooted at. + let root = paths::root(); + let text = replace_path(&text, &root, "[ROOT]"); + + text +} + +fn substitute_macros(input: &str) -> String { + let macros = [ + ("[RUNNING]", " Running"), + ("[COMPILING]", " Compiling"), + ("[CHECKING]", " Checking"), + ("[COMPLETED]", " Completed"), + ("[CREATED]", " Created"), + ("[FINISHED]", " Finished"), + ("[ERROR]", "error:"), + ("[WARNING]", "warning:"), + ("[NOTE]", "note:"), + ("[HELP]", "help:"), + ("[DOCUMENTING]", " Documenting"), + ("[FRESH]", " Fresh"), + ("[UPDATING]", " Updating"), + ("[ADDING]", " Adding"), + ("[REMOVING]", " Removing"), + ("[DOCTEST]", " Doc-tests"), + ("[PACKAGING]", " Packaging"), + ("[DOWNLOADING]", " Downloading"), + ("[DOWNLOADED]", " Downloaded"), + ("[UPLOADING]", " Uploading"), + ("[VERIFYING]", " Verifying"), + ("[ARCHIVING]", " Archiving"), + ("[INSTALLING]", " Installing"), + ("[REPLACING]", " Replacing"), + ("[UNPACKING]", " Unpacking"), + ("[SUMMARY]", " Summary"), + ("[FIXED]", " Fixed"), + ("[FIXING]", " Fixing"), + ("[EXE]", env::consts::EXE_SUFFIX), + ("[IGNORED]", " Ignored"), + ("[INSTALLED]", " Installed"), + ("[REPLACED]", " Replaced"), + ("[BUILDING]", " Building"), + ("[LOGIN]", " Login"), + ("[LOGOUT]", " Logout"), + ("[YANK]", " Yank"), + ("[OWNER]", " Owner"), + ("[MIGRATING]", " Migrating"), + ]; + let mut result = input.to_owned(); + for &(pat, subst) in ¯os { + result = result.replace(pat, subst) + } + result +} + +/// Compares one string against another, checking that they both match. +/// +/// See [Patterns](index.html#patterns) for more information on pattern matching. +/// +/// - `description` explains where the output is from (usually "stdout" or "stderr"). +/// - `other_output` is other output to display in the error (usually stdout or stderr). +pub fn match_exact( + expected: &str, + actual: &str, + description: &str, + other_output: &str, + cwd: Option<&Path>, +) -> Result<()> { + let expected = normalize_expected(expected, cwd); + let actual = normalize_actual(actual, cwd); + let e: Vec<_> = expected.lines().map(WildStr::new).collect(); + let a: Vec<_> = actual.lines().map(WildStr::new).collect(); + if e == a { + return Ok(()); + } + let diff = diff::colored_diff(&e, &a); + bail!( + "{} did not match:\n\ + {}\n\n\ + other output:\n\ + {}\n", + description, + diff, + other_output, + ); +} + +/// Convenience wrapper around [`match_exact`] which will panic on error. +#[track_caller] +pub fn assert_match_exact(expected: &str, actual: &str) { + if let Err(e) = match_exact(expected, actual, "", "", None) { + crate::panic_error("", e); + } +} + +/// Checks that the given string contains the given lines, ignoring the order +/// of the lines. +/// +/// See [Patterns](index.html#patterns) for more information on pattern matching. +pub fn match_unordered(expected: &str, actual: &str, cwd: Option<&Path>) -> Result<()> { + let expected = normalize_expected(expected, cwd); + let actual = normalize_actual(actual, cwd); + let e: Vec<_> = expected.lines().map(|line| WildStr::new(line)).collect(); + let mut a: Vec<_> = actual.lines().map(|line| WildStr::new(line)).collect(); + // match more-constrained lines first, although in theory we'll + // need some sort of recursive match here. This handles the case + // that you expect "a\n[..]b" and two lines are printed out, + // "ab\n"a", where technically we do match unordered but a naive + // search fails to find this. This simple sort at least gets the + // test suite to pass for now, but we may need to get more fancy + // if tests start failing again. + a.sort_by_key(|s| s.line.len()); + let mut changes = Vec::new(); + let mut a_index = 0; + let mut failure = false; + + use crate::diff::Change; + for (e_i, e_line) in e.into_iter().enumerate() { + match a.iter().position(|a_line| e_line == *a_line) { + Some(index) => { + let a_line = a.remove(index); + changes.push(Change::Keep(e_i, index, a_line)); + a_index += 1; + } + None => { + failure = true; + changes.push(Change::Remove(e_i, e_line)); + } + } + } + for unmatched in a { + failure = true; + changes.push(Change::Add(a_index, unmatched)); + a_index += 1; + } + if failure { + bail!( + "Expected lines did not match (ignoring order):\n{}\n", + diff::render_colored_changes(&changes) + ); + } else { + Ok(()) + } +} + +/// Checks that the given string contains the given contiguous lines +/// somewhere. +/// +/// See [Patterns](index.html#patterns) for more information on pattern matching. +pub fn match_contains(expected: &str, actual: &str, cwd: Option<&Path>) -> Result<()> { + let expected = normalize_expected(expected, cwd); + let actual = normalize_actual(actual, cwd); + let e: Vec<_> = expected.lines().map(|line| WildStr::new(line)).collect(); + let a: Vec<_> = actual.lines().map(|line| WildStr::new(line)).collect(); + if e.len() == 0 { + bail!("expected length must not be zero"); + } + for window in a.windows(e.len()) { + if window == e { + return Ok(()); + } + } + bail!( + "expected to find:\n\ + {}\n\n\ + did not find in output:\n\ + {}", + expected, + actual + ); +} + +/// Checks that the given string does not contain the given contiguous lines +/// anywhere. +/// +/// See [Patterns](index.html#patterns) for more information on pattern matching. +pub fn match_does_not_contain(expected: &str, actual: &str, cwd: Option<&Path>) -> Result<()> { + if match_contains(expected, actual, cwd).is_ok() { + bail!( + "expected not to find:\n\ + {}\n\n\ + but found in output:\n\ + {}", + expected, + actual + ); + } else { + Ok(()) + } +} + +/// Checks that the given string contains the given contiguous lines +/// somewhere, and should be repeated `number` times. +/// +/// See [Patterns](index.html#patterns) for more information on pattern matching. +pub fn match_contains_n( + expected: &str, + number: usize, + actual: &str, + cwd: Option<&Path>, +) -> Result<()> { + let expected = normalize_expected(expected, cwd); + let actual = normalize_actual(actual, cwd); + let e: Vec<_> = expected.lines().map(|line| WildStr::new(line)).collect(); + let a: Vec<_> = actual.lines().map(|line| WildStr::new(line)).collect(); + if e.len() == 0 { + bail!("expected length must not be zero"); + } + let matches = a.windows(e.len()).filter(|window| *window == e).count(); + if matches == number { + Ok(()) + } else { + bail!( + "expected to find {} occurrences of:\n\ + {}\n\n\ + but found {} matches in the output:\n\ + {}", + number, + expected, + matches, + actual + ) + } +} + +/// Checks that the given string has a line that contains the given patterns, +/// and that line also does not contain the `without` patterns. +/// +/// See [Patterns](index.html#patterns) for more information on pattern matching. +/// +/// See [`crate::Execs::with_stderr_line_without`] for an example and cautions +/// against using. +pub fn match_with_without( + actual: &str, + with: &[String], + without: &[String], + cwd: Option<&Path>, +) -> Result<()> { + let actual = normalize_actual(actual, cwd); + let norm = |s: &String| format!("[..]{}[..]", normalize_expected(s, cwd)); + let with: Vec<_> = with.iter().map(norm).collect(); + let without: Vec<_> = without.iter().map(norm).collect(); + let with_wild: Vec<_> = with.iter().map(|w| WildStr::new(w)).collect(); + let without_wild: Vec<_> = without.iter().map(|w| WildStr::new(w)).collect(); + + let matches: Vec<_> = actual + .lines() + .map(WildStr::new) + .filter(|line| with_wild.iter().all(|with| with == line)) + .filter(|line| !without_wild.iter().any(|without| without == line)) + .collect(); + match matches.len() { + 0 => bail!( + "Could not find expected line in output.\n\ + With contents: {:?}\n\ + Without contents: {:?}\n\ + Actual stderr:\n\ + {}\n", + with, + without, + actual + ), + 1 => Ok(()), + _ => bail!( + "Found multiple matching lines, but only expected one.\n\ + With contents: {:?}\n\ + Without contents: {:?}\n\ + Matching lines:\n\ + {}\n", + with, + without, + itertools::join(matches, "\n") + ), + } +} + +/// Checks that the given string of JSON objects match the given set of +/// expected JSON objects. +/// +/// See [`crate::Execs::with_json`] for more details. +pub fn match_json(expected: &str, actual: &str, cwd: Option<&Path>) -> Result<()> { + let (exp_objs, act_objs) = collect_json_objects(expected, actual)?; + if exp_objs.len() != act_objs.len() { + bail!( + "expected {} json lines, got {}, stdout:\n{}", + exp_objs.len(), + act_objs.len(), + actual + ); + } + for (exp_obj, act_obj) in exp_objs.iter().zip(act_objs) { + find_json_mismatch(exp_obj, &act_obj, cwd)?; + } + Ok(()) +} + +/// Checks that the given string of JSON objects match the given set of +/// expected JSON objects, ignoring their order. +/// +/// See [`crate::Execs::with_json_contains_unordered`] for more details and +/// cautions when using. +pub fn match_json_contains_unordered( + expected: &str, + actual: &str, + cwd: Option<&Path>, +) -> Result<()> { + let (exp_objs, mut act_objs) = collect_json_objects(expected, actual)?; + for exp_obj in exp_objs { + match act_objs + .iter() + .position(|act_obj| find_json_mismatch(&exp_obj, act_obj, cwd).is_ok()) + { + Some(index) => act_objs.remove(index), + None => { + bail!( + "Did not find expected JSON:\n\ + {}\n\ + Remaining available output:\n\ + {}\n", + serde_json::to_string_pretty(&exp_obj).unwrap(), + itertools::join( + act_objs.iter().map(|o| serde_json::to_string(o).unwrap()), + "\n" + ) + ); + } + }; + } + Ok(()) +} + +fn collect_json_objects( + expected: &str, + actual: &str, +) -> Result<(Vec, Vec)> { + let expected_objs: Vec<_> = expected + .split("\n\n") + .map(|expect| { + expect + .parse() + .with_context(|| format!("failed to parse expected JSON object:\n{}", expect)) + }) + .collect::>()?; + let actual_objs: Vec<_> = actual + .lines() + .filter(|line| line.starts_with('{')) + .map(|line| { + line.parse() + .with_context(|| format!("failed to parse JSON object:\n{}", line)) + }) + .collect::>()?; + Ok((expected_objs, actual_objs)) +} + +/// Compares JSON object for approximate equality. +/// You can use `[..]` wildcard in strings (useful for OS-dependent things such +/// as paths). You can use a `"{...}"` string literal as a wildcard for +/// arbitrary nested JSON (useful for parts of object emitted by other programs +/// (e.g., rustc) rather than Cargo itself). +pub fn find_json_mismatch(expected: &Value, actual: &Value, cwd: Option<&Path>) -> Result<()> { + match find_json_mismatch_r(expected, actual, cwd) { + Some((expected_part, actual_part)) => bail!( + "JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n", + serde_json::to_string_pretty(expected).unwrap(), + serde_json::to_string_pretty(&actual).unwrap(), + serde_json::to_string_pretty(expected_part).unwrap(), + serde_json::to_string_pretty(actual_part).unwrap(), + ), + None => Ok(()), + } +} + +fn find_json_mismatch_r<'a>( + expected: &'a Value, + actual: &'a Value, + cwd: Option<&Path>, +) -> Option<(&'a Value, &'a Value)> { + use serde_json::Value::*; + match (expected, actual) { + (&Number(ref l), &Number(ref r)) if l == r => None, + (&Bool(l), &Bool(r)) if l == r => None, + (&String(ref l), _) if l == "{...}" => None, + (&String(ref l), &String(ref r)) => { + if match_exact(l, r, "", "", cwd).is_err() { + Some((expected, actual)) + } else { + None + } + } + (&Array(ref l), &Array(ref r)) => { + if l.len() != r.len() { + return Some((expected, actual)); + } + + l.iter() + .zip(r.iter()) + .filter_map(|(l, r)| find_json_mismatch_r(l, r, cwd)) + .next() + } + (&Object(ref l), &Object(ref r)) => { + let same_keys = l.len() == r.len() && l.keys().all(|k| r.contains_key(k)); + if !same_keys { + return Some((expected, actual)); + } + + l.values() + .zip(r.values()) + .filter_map(|(l, r)| find_json_mismatch_r(l, r, cwd)) + .next() + } + (&Null, &Null) => None, + // Magic string literal `"{...}"` acts as wildcard for any sub-JSON. + _ => Some((expected, actual)), + } +} + +/// A single line string that supports `[..]` wildcard matching. +pub struct WildStr<'a> { + has_meta: bool, + line: &'a str, +} + +impl<'a> WildStr<'a> { + pub fn new(line: &'a str) -> WildStr<'a> { + WildStr { + has_meta: line.contains("[..]"), + line, + } + } +} + +impl<'a> PartialEq for WildStr<'a> { + fn eq(&self, other: &Self) -> bool { + match (self.has_meta, other.has_meta) { + (false, false) => self.line == other.line, + (true, false) => meta_cmp(self.line, other.line), + (false, true) => meta_cmp(other.line, self.line), + (true, true) => panic!("both lines cannot have [..]"), + } + } +} + +fn meta_cmp(a: &str, mut b: &str) -> bool { + for (i, part) in a.split("[..]").enumerate() { + match b.find(part) { + Some(j) => { + if i == 0 && j != 0 { + return false; + } + b = &b[j + part.len()..]; + } + None => return false, + } + } + b.is_empty() || a.ends_with("[..]") +} + +impl fmt::Display for WildStr<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(&self.line) + } +} + +impl fmt::Debug for WildStr<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self.line) + } +} + +#[test] +fn wild_str_cmp() { + for (a, b) in &[ + ("a b", "a b"), + ("a[..]b", "a b"), + ("a[..]", "a b"), + ("[..]", "a b"), + ("[..]b", "a b"), + ] { + assert_eq!(WildStr::new(a), WildStr::new(b)); + } + for (a, b) in &[("[..]b", "c"), ("b", "c"), ("b", "cb")] { + assert_ne!(WildStr::new(a), WildStr::new(b)); + } +} diff -Nru cargo-0.54.0/crates/cargo-test-support/src/diff.rs cargo-0.58.0/crates/cargo-test-support/src/diff.rs --- cargo-0.54.0/crates/cargo-test-support/src/diff.rs 1970-01-01 00:00:00.000000000 +0000 +++ cargo-0.58.0/crates/cargo-test-support/src/diff.rs 2021-10-21 14:30:11.000000000 +0000 @@ -0,0 +1,174 @@ +//! A simple Myers diff implementation. +//! +//! This focuses on being short and simple, and the expense of being +//! inefficient. A key characteristic here is that this supports cargotest's +//! `[..]` wildcard matching. That means things like hashing can't be used. +//! Since Cargo's output tends to be small, this should be sufficient. + +use std::fmt; +use std::io::Write; +use termcolor::{Ansi, Color, ColorSpec, NoColor, WriteColor}; + +/// A single line change to be applied to the original. +#[derive(Debug, Eq, PartialEq)] +pub enum Change { + Add(usize, T), + Remove(usize, T), + Keep(usize, usize, T), +} + +pub fn diff<'a, T>(a: &'a [T], b: &'a [T]) -> Vec> +where + T: PartialEq, +{ + if a.is_empty() && b.is_empty() { + return vec![]; + } + let mut diff = vec![]; + for (prev_x, prev_y, x, y) in backtrack(&a, &b) { + if x == prev_x { + diff.push(Change::Add(prev_y + 1, &b[prev_y])); + } else if y == prev_y { + diff.push(Change::Remove(prev_x + 1, &a[prev_x])); + } else { + diff.push(Change::Keep(prev_x + 1, prev_y + 1, &a[prev_x])); + } + } + diff.reverse(); + diff +} + +fn shortest_edit(a: &[T], b: &[T]) -> Vec> +where + T: PartialEq, +{ + let max = a.len() + b.len(); + let mut v = vec![0; 2 * max + 1]; + let mut trace = vec![]; + for d in 0..=max { + trace.push(v.clone()); + for k in (0..=(2 * d)).step_by(2) { + let mut x = if k == 0 || (k != 2 * d && v[max - d + k - 1] < v[max - d + k + 1]) { + // Move down + v[max - d + k + 1] + } else { + // Move right + v[max - d + k - 1] + 1 + }; + let mut y = x + d - k; + // Step diagonally as far as possible. + while x < a.len() && y < b.len() && a[x] == b[y] { + x += 1; + y += 1; + } + v[max - d + k] = x; + // Return if reached the bottom-right position. + if x >= a.len() && y >= b.len() { + return trace; + } + } + } + panic!("finished without hitting end?"); +} + +fn backtrack(a: &[T], b: &[T]) -> Vec<(usize, usize, usize, usize)> +where + T: PartialEq, +{ + let mut result = vec![]; + let mut x = a.len(); + let mut y = b.len(); + let max = x + y; + for (d, v) in shortest_edit(a, b).iter().enumerate().rev() { + let k = x + d - y; + let prev_k = if k == 0 || (k != 2 * d && v[max - d + k - 1] < v[max - d + k + 1]) { + k + 1 + } else { + k - 1 + }; + let prev_x = v[max - d + prev_k]; + let prev_y = (prev_x + d).saturating_sub(prev_k); + while x > prev_x && y > prev_y { + result.push((x - 1, y - 1, x, y)); + x -= 1; + y -= 1; + } + if d > 0 { + result.push((prev_x, prev_y, x, y)); + } + x = prev_x; + y = prev_y; + } + return result; +} + +pub fn colored_diff<'a, T>(a: &'a [T], b: &'a [T]) -> String +where + T: PartialEq + fmt::Display, +{ + let changes = diff(a, b); + render_colored_changes(&changes) +} + +pub fn render_colored_changes(changes: &[Change]) -> String { + // termcolor is not very ergonomic, but I don't want to bring in another dependency. + let mut red = ColorSpec::new(); + red.set_fg(Some(Color::Red)); + let mut green = ColorSpec::new(); + green.set_fg(Some(Color::Green)); + let mut dim = ColorSpec::new(); + dim.set_dimmed(true); + let mut v = Vec::new(); + let mut result: Box = if crate::is_ci() { + // Don't use color on CI. Even though GitHub can display colors, it + // makes reading the raw logs more difficult. + Box::new(NoColor::new(&mut v)) + } else { + Box::new(Ansi::new(&mut v)) + }; + + for change in changes { + let (nums, sign, color, text) = match change { + Change::Add(i, s) => (format!(" {:<4} ", i), '+', &green, s), + Change::Remove(i, s) => (format!("{:<4} ", i), '-', &red, s), + Change::Keep(x, y, s) => (format!("{:<4}{:<4} ", x, y), ' ', &dim, s), + }; + result.set_color(&dim).unwrap(); + write!(result, "{}", nums).unwrap(); + let mut bold = color.clone(); + bold.set_bold(true); + result.set_color(&bold).unwrap(); + write!(result, "{}", sign).unwrap(); + result.reset().unwrap(); + result.set_color(&color).unwrap(); + write!(result, "{}", text).unwrap(); + result.reset().unwrap(); + writeln!(result).unwrap(); + } + drop(result); + String::from_utf8(v).unwrap() +} + +#[cfg(test)] +pub fn compare(a: &str, b: &str) { + let a: Vec<_> = a.chars().collect(); + let b: Vec<_> = b.chars().collect(); + let changes = diff(&a, &b); + let mut result = vec![]; + for change in changes { + match change { + Change::Add(_, s) => result.push(*s), + Change::Remove(_, _s) => {} + Change::Keep(_, _, s) => result.push(*s), + } + } + assert_eq!(b, result); +} + +#[test] +fn basic_tests() { + compare("", ""); + compare("A", ""); + compare("", "B"); + compare("ABCABBA", "CBABAC"); +} diff -Nru cargo-0.54.0/crates/cargo-test-support/src/git.rs cargo-0.58.0/crates/cargo-test-support/src/git.rs --- cargo-0.54.0/crates/cargo-test-support/src/git.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/crates/cargo-test-support/src/git.rs 2021-10-21 14:30:11.000000000 +0000 @@ -132,11 +132,12 @@ } 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)); diff -Nru cargo-0.54.0/crates/cargo-test-support/src/lib.rs cargo-0.58.0/crates/cargo-test-support/src/lib.rs --- cargo-0.54.0/crates/cargo-test-support/src/lib.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/crates/cargo-test-support/src/lib.rs 2021-10-21 14:30:11.000000000 +0000 @@ -1,6 +1,6 @@ //! # Cargo test support. //! -//! See https://rust-lang.github.io/cargo/contrib/ for a guide on writing tests. +//! See for a guide on writing tests. #![allow(clippy::all)] #![warn(clippy::needless_borrow)] @@ -8,7 +8,7 @@ use std::env; use std::ffi::OsStr; -use std::fmt; +use std::fmt::Write; use std::fs; use std::os; use std::path::{Path, PathBuf}; @@ -16,8 +16,9 @@ use std::str; use std::time::{self, Duration}; +use anyhow::{bail, Result}; use cargo_util::{is_ci, ProcessBuilder, ProcessError}; -use serde_json::{self, Value}; +use serde_json; use url::Url; use self::paths::CargoPathExt; @@ -27,18 +28,37 @@ ($e:expr) => { match $e { Ok(e) => e, - Err(e) => panic!("{} failed with {}", stringify!($e), e), + Err(e) => $crate::panic_error(&format!("failed running {}", stringify!($e)), e), } }; } +#[track_caller] +pub fn panic_error(what: &str, err: impl Into) -> ! { + let err = err.into(); + pe(what, err); + #[track_caller] + fn pe(what: &str, err: anyhow::Error) -> ! { + let mut result = format!("{}\nerror: {}", what, err); + for cause in err.chain().skip(1) { + drop(writeln!(result, "\nCaused by:")); + drop(write!(result, "{}", cause)); + } + panic!("\n{}", result); + } +} + pub use cargo_test_macro::cargo_test; +pub mod compare; pub mod cross_compile; +mod diff; pub mod git; +pub mod install; pub mod paths; pub mod publish; pub mod registry; +pub mod tools; /* * @@ -50,20 +70,36 @@ struct FileBuilder { path: PathBuf, body: String, + executable: bool, } impl FileBuilder { - pub fn new(path: PathBuf, body: &str) -> FileBuilder { + pub fn new(path: PathBuf, body: &str, executable: bool) -> FileBuilder { FileBuilder { path, body: body.to_string(), + executable: executable, } } - fn mk(&self) { + fn mk(&mut self) { + if self.executable { + self.path.set_extension(env::consts::EXE_EXTENSION); + } + self.dirname().mkdir_p(); fs::write(&self.path, &self.body) .unwrap_or_else(|e| panic!("could not create file {}: {}", self.path.display(), e)); + + #[cfg(unix)] + if self.executable { + use std::os::unix::fs::PermissionsExt; + + let mut perms = fs::metadata(&self.path).unwrap().permissions(); + let mode = perms.mode(); + perms.set_mode(mode | 0o111); + fs::set_permissions(&self.path, perms).unwrap(); + } } fn dirname(&self) -> &Path { @@ -102,11 +138,16 @@ } #[cfg(windows)] - fn mk(&self) { + fn mk(&mut self) { self.dirname().mkdir_p(); if self.src_is_dir { t!(os::windows::fs::symlink_dir(&self.dst, &self.src)); } else { + if let Some(ext) = self.dst.extension() { + if ext == env::consts::EXE_EXTENSION { + self.src.set_extension(ext); + } + } t!(os::windows::fs::symlink_file(&self.dst, &self.src)); } } @@ -157,13 +198,22 @@ /// Adds a file to the project. pub fn file>(mut self, path: B, body: &str) -> Self { - self._file(path.as_ref(), body); + self._file(path.as_ref(), body, false); + self + } + + /// Adds an executable file to the project. + pub fn executable>(mut self, path: B, body: &str) -> Self { + self._file(path.as_ref(), body, true); self } - fn _file(&mut self, path: &Path, body: &str) { - self.files - .push(FileBuilder::new(self.root.root().join(path), body)); + fn _file(&mut self, path: &Path, body: &str, executable: bool) { + self.files.push(FileBuilder::new( + self.root.root().join(path), + body, + executable, + )); } /// Adds a symlink to a file to the project. @@ -199,13 +249,17 @@ let manifest_path = self.root.root().join("Cargo.toml"); if !self.no_manifest && self.files.iter().all(|fb| fb.path != manifest_path) { - self._file(Path::new("Cargo.toml"), &basic_manifest("foo", "0.0.1")) + self._file( + Path::new("Cargo.toml"), + &basic_manifest("foo", "0.0.1"), + false, + ) } let past = time::SystemTime::now() - Duration::new(1, 0); let ftime = filetime::FileTime::from_system_time(past); - for file in self.files.iter() { + for file in self.files.iter_mut() { file.mk(); if is_coarse_mtime() { // Place the entire project 1 second in the past to ensure @@ -217,7 +271,7 @@ } } - for symlink in self.symlinks.iter() { + for symlink in self.symlinks.iter_mut() { symlink.mk(); } @@ -296,7 +350,7 @@ /// Changes the contents of an existing file. pub fn change_file(&self, path: &str, body: &str) { - FileBuilder::new(self.root().join(path), body).mk() + FileBuilder::new(self.root().join(path), body, false).mk() } /// Creates a `ProcessBuilder` to run a program in the project @@ -412,19 +466,6 @@ buf } -trait ErrMsg { - fn with_err_msg(self, val: String) -> Result; -} - -impl ErrMsg for Result { - fn with_err_msg(self, val: String) -> Result { - match self { - Ok(val) => Ok(val), - Err(err) => Err(format!("{}; original={}", val, err)), - } - } -} - // Path to cargo executables pub fn cargo_dir() -> PathBuf { env::var_os("CARGO_BIN_PATH") @@ -445,13 +486,18 @@ cargo_dir().join(format!("cargo{}", env::consts::EXE_SUFFIX)) } -/* - * - * ===== Matchers ===== - * - */ - -pub type MatchResult = Result<(), String>; +/// This is the raw output from the process. +/// +/// This is similar to `std::process::Output`, however the `status` is +/// translated to the raw `code`. This is necessary because `ProcessError` +/// does not have access to the raw `ExitStatus` because `ProcessError` needs +/// to be serializable (for the Rustc cache), and `ExitStatus` does not +/// provide a constructor. +pub struct RawOutput { + pub code: Option, + pub stdout: Vec, + pub stderr: Vec, +} #[must_use] #[derive(Clone)] @@ -464,15 +510,13 @@ expect_exit_code: Option, expect_stdout_contains: Vec, expect_stderr_contains: Vec, - expect_either_contains: Vec, expect_stdout_contains_n: Vec<(String, usize)>, expect_stdout_not_contains: Vec, expect_stderr_not_contains: Vec, expect_stderr_unordered: Vec, - expect_neither_contains: Vec, expect_stderr_with_without: Vec<(Vec, Vec)>, - expect_json: Option>, - expect_json_contains_unordered: Vec, + expect_json: Option, + expect_json_contains_unordered: Option, stream_output: bool, } @@ -483,14 +527,14 @@ } /// Verifies that stdout is equal to the given lines. - /// See `lines_match` for supported patterns. + /// See [`compare`] for supported patterns. pub fn with_stdout(&mut self, expected: S) -> &mut Self { self.expect_stdout = Some(expected.to_string()); self } /// Verifies that stderr is equal to the given lines. - /// See `lines_match` for supported patterns. + /// See [`compare`] for supported patterns. pub fn with_stderr(&mut self, expected: S) -> &mut Self { self.expect_stderr = Some(expected.to_string()); self @@ -514,7 +558,8 @@ /// Verifies that stdout contains the given contiguous lines somewhere in /// its output. - /// See `lines_match` for supported patterns. + /// + /// See [`compare`] for supported patterns. pub fn with_stdout_contains(&mut self, expected: S) -> &mut Self { self.expect_stdout_contains.push(expected.to_string()); self @@ -522,23 +567,17 @@ /// Verifies that stderr contains the given contiguous lines somewhere in /// its output. - /// See `lines_match` for supported patterns. + /// + /// See [`compare`] for supported patterns. pub fn with_stderr_contains(&mut self, expected: S) -> &mut Self { self.expect_stderr_contains.push(expected.to_string()); self } - /// Verifies that either stdout or stderr contains the given contiguous - /// lines somewhere in its output. - /// See `lines_match` for supported patterns. - pub fn with_either_contains(&mut self, expected: S) -> &mut Self { - self.expect_either_contains.push(expected.to_string()); - self - } - /// Verifies that stdout contains the given contiguous lines somewhere in /// its output, and should be repeated `number` times. - /// See `lines_match` for supported patterns. + /// + /// See [`compare`] for supported patterns. pub fn with_stdout_contains_n(&mut self, expected: S, number: usize) -> &mut Self { self.expect_stdout_contains_n .push((expected.to_string(), number)); @@ -546,15 +585,18 @@ } /// Verifies that stdout does not contain the given contiguous lines. - /// See `lines_match` for supported patterns. - /// See note on `with_stderr_does_not_contain`. + /// + /// See [`compare`] for supported patterns. + /// + /// See note on [`Self::with_stderr_does_not_contain`]. pub fn with_stdout_does_not_contain(&mut self, expected: S) -> &mut Self { self.expect_stdout_not_contains.push(expected.to_string()); self } /// Verifies that stderr does not contain the given contiguous lines. - /// See `lines_match` for supported patterns. + /// + /// See [`compare`] for supported patterns. /// /// Care should be taken when using this method because there is a /// limitless number of possible things that *won't* appear. A typo means @@ -568,7 +610,9 @@ /// Verifies that all of the stderr output is equal to the given lines, /// ignoring the order of the lines. - /// See `lines_match` for supported patterns. + /// + /// See [`compare`] for supported patterns. + /// /// This is useful when checking the output of `cargo build -v` since /// the order of the output is not always deterministic. /// Recommend use `with_stderr_contains` instead unless you really want to @@ -578,8 +622,10 @@ /// with multiple lines that might match, and this is not smart enough to /// do anything like longest-match. For example, avoid something like: /// - /// [RUNNING] `rustc [..] - /// [RUNNING] `rustc --crate-name foo [..] + /// ```text + /// [RUNNING] `rustc [..] + /// [RUNNING] `rustc --crate-name foo [..] + /// ``` /// /// This will randomly fail if the other crate name is `bar`, and the /// order changes. @@ -620,28 +666,28 @@ } /// Verifies the JSON output matches the given JSON. - /// Typically used when testing cargo commands that emit JSON. + /// + /// This is typically used when testing cargo commands that emit JSON. /// Each separate JSON object should be separated by a blank line. /// Example: - /// assert_that( - /// p.cargo("metadata"), - /// execs().with_json(r#" - /// {"example": "abc"} - /// - /// {"example": "def"} - /// "#) - /// ); - /// Objects should match in the order given. - /// The order of arrays is ignored. - /// Strings support patterns described in `lines_match`. - /// Use `{...}` to match any object. + /// + /// ```rust,ignore + /// assert_that( + /// p.cargo("metadata"), + /// execs().with_json(r#" + /// {"example": "abc"} + /// + /// {"example": "def"} + /// "#) + /// ); + /// ``` + /// + /// - Objects should match in the order given. + /// - The order of arrays is ignored. + /// - Strings support patterns described in [`compare`]. + /// - Use `"{...}"` to match any object. pub fn with_json(&mut self, expected: &str) -> &mut Self { - self.expect_json = Some( - expected - .split("\n\n") - .map(|line| line.to_string()) - .collect(), - ); + self.expect_json = Some(expected.to_string()); self } @@ -655,8 +701,13 @@ /// /// See `with_json` for more detail. pub fn with_json_contains_unordered(&mut self, expected: &str) -> &mut Self { - self.expect_json_contains_unordered - .extend(expected.split("\n\n").map(|line| line.to_string())); + match &mut self.expect_json_contains_unordered { + None => self.expect_json_contains_unordered = Some(expected.to_string()), + Some(e) => { + e.push_str("\n\n"); + e.push_str(expected); + } + } self } @@ -688,6 +739,10 @@ self } + fn get_cwd(&self) -> Option<&Path> { + self.process_builder.as_ref().and_then(|p| p.get_cwd()) + } + pub fn env>(&mut self, key: &str, val: T) -> &mut Self { if let Some(ref mut p) = self.process_builder { p.env(key, val); @@ -702,7 +757,7 @@ self } - pub fn exec_with_output(&mut self) -> anyhow::Result { + pub fn exec_with_output(&mut self) -> Result { self.ran = true; // TODO avoid unwrap let p = (&self.process_builder).clone().unwrap(); @@ -738,46 +793,63 @@ self.ran = true; let p = (&self.process_builder).clone().unwrap(); if let Err(e) = self.match_process(&p) { - panic!("\nExpected: {:?}\n but: {}", self, e) + panic_error(&format!("test failed running {}", p), e); + } + } + + /// Runs the process, checks the expected output, and returns the first + /// JSON object on stdout. + #[track_caller] + pub fn run_json(&mut self) -> serde_json::Value { + self.ran = true; + let p = (&self.process_builder).clone().unwrap(); + match self.match_process(&p) { + Err(e) => panic_error(&format!("test failed running {}", p), e), + Ok(output) => serde_json::from_slice(&output.stdout).unwrap_or_else(|e| { + panic!( + "\nfailed to parse JSON: {}\n\ + output was:\n{}\n", + e, + String::from_utf8_lossy(&output.stdout) + ); + }), } } #[track_caller] pub fn run_output(&mut self, output: &Output) { self.ran = true; - if let Err(e) = self.match_output(output) { - panic!("\nExpected: {:?}\n but: {}", self, e) + if let Err(e) = self.match_output(output.status.code(), &output.stdout, &output.stderr) { + panic_error("process did not return the expected result", e) } } - fn verify_checks_output(&self, output: &Output) { + fn verify_checks_output(&self, stdout: &[u8], stderr: &[u8]) { if self.expect_exit_code.unwrap_or(0) != 0 && self.expect_stdout.is_none() && self.expect_stdin.is_none() && self.expect_stderr.is_none() && self.expect_stdout_contains.is_empty() && self.expect_stderr_contains.is_empty() - && self.expect_either_contains.is_empty() && self.expect_stdout_contains_n.is_empty() && self.expect_stdout_not_contains.is_empty() && self.expect_stderr_not_contains.is_empty() && self.expect_stderr_unordered.is_empty() - && self.expect_neither_contains.is_empty() && self.expect_stderr_with_without.is_empty() && self.expect_json.is_none() - && self.expect_json_contains_unordered.is_empty() + && self.expect_json_contains_unordered.is_none() { panic!( "`with_status()` is used, but no output is checked.\n\ The test must check the output to ensure the correct error is triggered.\n\ --- stdout\n{}\n--- stderr\n{}", - String::from_utf8_lossy(&output.stdout), - String::from_utf8_lossy(&output.stderr), + String::from_utf8_lossy(stdout), + String::from_utf8_lossy(stderr), ); } } - fn match_process(&self, process: &ProcessBuilder) -> MatchResult { + fn match_process(&self, process: &ProcessBuilder) -> Result { println!("running {}", process); let res = if self.stream_output { if is_ci() { @@ -799,7 +871,14 @@ }; match res { - Ok(out) => self.match_output(&out), + Ok(out) => { + self.match_output(out.status.code(), &out.stdout, &out.stderr)?; + return Ok(RawOutput { + stdout: out.stdout, + stderr: out.stderr, + code: out.status.code(), + }); + } Err(e) => { if let Some(ProcessError { stdout: Some(stdout), @@ -808,383 +887,73 @@ .. }) = e.downcast_ref::() { - return self - .match_status(*code, stdout, stderr) - .and(self.match_stdout(stdout, stderr)) - .and(self.match_stderr(stdout, stderr)); + self.match_output(*code, stdout, stderr)?; + return Ok(RawOutput { + stdout: stdout.to_vec(), + stderr: stderr.to_vec(), + code: *code, + }); } - Err(format!("could not exec process {}: {:?}", process, e)) + bail!("could not exec process {}: {:?}", process, e) } } } - fn match_output(&self, actual: &Output) -> MatchResult { - self.verify_checks_output(actual); - self.match_status(actual.status.code(), &actual.stdout, &actual.stderr) - .and(self.match_stdout(&actual.stdout, &actual.stderr)) - .and(self.match_stderr(&actual.stdout, &actual.stderr)) - } + fn match_output(&self, code: Option, stdout: &[u8], stderr: &[u8]) -> Result<()> { + self.verify_checks_output(stdout, stderr); + let stdout = str::from_utf8(stdout).expect("stdout is not utf8"); + let stderr = str::from_utf8(stderr).expect("stderr is not utf8"); + let cwd = self.get_cwd(); - fn match_status(&self, code: Option, stdout: &[u8], stderr: &[u8]) -> MatchResult { match self.expect_exit_code { - None => Ok(()), - Some(expected) if code == Some(expected) => Ok(()), - Some(_) => Err(format!( - "exited with {:?}\n--- stdout\n{}\n--- stderr\n{}", - code, - String::from_utf8_lossy(stdout), - String::from_utf8_lossy(stderr) - )), + None => {} + Some(expected) if code == Some(expected) => {} + Some(expected) => bail!( + "process exited with code {} (expected {})\n--- stdout\n{}\n--- stderr\n{}", + code.unwrap_or(-1), + expected, + stdout, + stderr + ), } - } - fn match_stdout(&self, stdout: &[u8], stderr: &[u8]) -> MatchResult { - self.match_std( - self.expect_stdout.as_ref(), - stdout, - "stdout", - stderr, - MatchKind::Exact, - )?; + if let Some(expect_stdout) = &self.expect_stdout { + compare::match_exact(expect_stdout, stdout, "stdout", stderr, cwd)?; + } + if let Some(expect_stderr) = &self.expect_stderr { + compare::match_exact(expect_stderr, stderr, "stderr", stdout, cwd)?; + } for expect in self.expect_stdout_contains.iter() { - self.match_std(Some(expect), stdout, "stdout", stderr, MatchKind::Partial)?; + compare::match_contains(expect, stdout, cwd)?; } for expect in self.expect_stderr_contains.iter() { - self.match_std(Some(expect), stderr, "stderr", stdout, MatchKind::Partial)?; + compare::match_contains(expect, stderr, cwd)?; } for &(ref expect, number) in self.expect_stdout_contains_n.iter() { - self.match_std( - Some(expect), - stdout, - "stdout", - stderr, - MatchKind::PartialN(number), - )?; + compare::match_contains_n(expect, number, stdout, cwd)?; } for expect in self.expect_stdout_not_contains.iter() { - self.match_std( - Some(expect), - stdout, - "stdout", - stderr, - MatchKind::NotPresent, - )?; + compare::match_does_not_contain(expect, stdout, cwd)?; } for expect in self.expect_stderr_not_contains.iter() { - self.match_std( - Some(expect), - stderr, - "stderr", - stdout, - MatchKind::NotPresent, - )?; + compare::match_does_not_contain(expect, stderr, cwd)?; } for expect in self.expect_stderr_unordered.iter() { - self.match_std(Some(expect), stderr, "stderr", stdout, MatchKind::Unordered)?; - } - for expect in self.expect_neither_contains.iter() { - self.match_std( - Some(expect), - stdout, - "stdout", - stdout, - MatchKind::NotPresent, - )?; - - self.match_std( - Some(expect), - stderr, - "stderr", - stderr, - MatchKind::NotPresent, - )?; - } - - for expect in self.expect_either_contains.iter() { - let match_std = - self.match_std(Some(expect), stdout, "stdout", stdout, MatchKind::Partial); - let match_err = - self.match_std(Some(expect), stderr, "stderr", stderr, MatchKind::Partial); - - if let (Err(_), Err(_)) = (match_std, match_err) { - return Err(format!( - "expected to find:\n\ - {}\n\n\ - did not find in either output.", - expect - )); - } + compare::match_unordered(expect, stderr, cwd)?; } - for (with, without) in self.expect_stderr_with_without.iter() { - self.match_with_without(stderr, with, without)?; + compare::match_with_without(stderr, with, without, cwd)?; } - if let Some(ref objects) = self.expect_json { - let stdout = - str::from_utf8(stdout).map_err(|_| "stdout was not utf8 encoded".to_owned())?; - let lines = stdout - .lines() - .filter(|line| line.starts_with('{')) - .collect::>(); - if lines.len() != objects.len() { - return Err(format!( - "expected {} json lines, got {}, stdout:\n{}", - objects.len(), - lines.len(), - stdout - )); - } - for (obj, line) in objects.iter().zip(lines) { - self.match_json(obj, line)?; - } + if let Some(ref expect_json) = self.expect_json { + compare::match_json(expect_json, stdout, cwd)?; } - if !self.expect_json_contains_unordered.is_empty() { - let stdout = - str::from_utf8(stdout).map_err(|_| "stdout was not utf8 encoded".to_owned())?; - let mut lines = stdout - .lines() - .filter(|line| line.starts_with('{')) - .collect::>(); - for obj in &self.expect_json_contains_unordered { - match lines - .iter() - .position(|line| self.match_json(obj, line).is_ok()) - { - Some(index) => lines.remove(index), - None => { - return Err(format!( - "Did not find expected JSON:\n\ - {}\n\ - Remaining available output:\n\ - {}\n", - serde_json::to_string_pretty(obj).unwrap(), - lines.join("\n") - )); - } - }; - } + if let Some(ref expected) = self.expect_json_contains_unordered { + compare::match_json_contains_unordered(expected, stdout, cwd)?; } Ok(()) } - - fn match_stderr(&self, stdout: &[u8], stderr: &[u8]) -> MatchResult { - self.match_std( - self.expect_stderr.as_ref(), - stderr, - "stderr", - stdout, - MatchKind::Exact, - ) - } - - fn normalize_actual(&self, description: &str, actual: &[u8]) -> Result { - let actual = match str::from_utf8(actual) { - Err(..) => return Err(format!("{} was not utf8 encoded", description)), - Ok(actual) => actual, - }; - Ok(self.normalize_matcher(actual)) - } - - fn normalize_matcher(&self, matcher: &str) -> String { - normalize_matcher( - matcher, - self.process_builder.as_ref().and_then(|p| p.get_cwd()), - ) - } - - fn match_std( - &self, - expected: Option<&String>, - actual: &[u8], - description: &str, - extra: &[u8], - kind: MatchKind, - ) -> MatchResult { - let out = match expected { - Some(out) => self.normalize_matcher(out), - None => return Ok(()), - }; - - let actual = self.normalize_actual(description, actual)?; - - match kind { - MatchKind::Exact => { - let a = actual.lines(); - let e = out.lines(); - - let diffs = self.diff_lines(a, e, false); - if diffs.is_empty() { - Ok(()) - } else { - Err(format!( - "differences:\n\ - {}\n\n\ - other output:\n\ - `{}`", - diffs.join("\n"), - String::from_utf8_lossy(extra) - )) - } - } - MatchKind::Partial => { - let mut a = actual.lines(); - let e = out.lines(); - - let mut diffs = self.diff_lines(a.clone(), e.clone(), true); - while a.next().is_some() { - let a = self.diff_lines(a.clone(), e.clone(), true); - if a.len() < diffs.len() { - diffs = a; - } - } - if diffs.is_empty() { - Ok(()) - } else { - Err(format!( - "expected to find:\n\ - {}\n\n\ - did not find in output:\n\ - {}", - out, actual - )) - } - } - MatchKind::PartialN(number) => { - let mut a = actual.lines(); - let e = out.lines(); - - let mut matches = 0; - - while let Some(..) = { - if self.diff_lines(a.clone(), e.clone(), true).is_empty() { - matches += 1; - } - a.next() - } {} - - if matches == number { - Ok(()) - } else { - Err(format!( - "expected to find {} occurrences:\n\ - {}\n\n\ - did not find in output:\n\ - {}", - number, out, actual - )) - } - } - MatchKind::NotPresent => { - let mut a = actual.lines(); - let e = out.lines(); - - let mut diffs = self.diff_lines(a.clone(), e.clone(), true); - while a.next().is_some() { - let a = self.diff_lines(a.clone(), e.clone(), true); - if a.len() < diffs.len() { - diffs = a; - } - } - if diffs.is_empty() { - Err(format!( - "expected not to find:\n\ - {}\n\n\ - but found in output:\n\ - {}", - out, actual - )) - } else { - Ok(()) - } - } - MatchKind::Unordered => lines_match_unordered(&out, &actual), - } - } - - fn match_with_without( - &self, - actual: &[u8], - with: &[String], - without: &[String], - ) -> MatchResult { - let actual = self.normalize_actual("stderr", actual)?; - let contains = |s, line| { - let mut s = self.normalize_matcher(s); - s.insert_str(0, "[..]"); - s.push_str("[..]"); - lines_match(&s, line) - }; - let matches: Vec<&str> = actual - .lines() - .filter(|line| with.iter().all(|with| contains(with, line))) - .filter(|line| !without.iter().any(|without| contains(without, line))) - .collect(); - match matches.len() { - 0 => Err(format!( - "Could not find expected line in output.\n\ - With contents: {:?}\n\ - Without contents: {:?}\n\ - Actual stderr:\n\ - {}\n", - with, without, actual - )), - 1 => Ok(()), - _ => Err(format!( - "Found multiple matching lines, but only expected one.\n\ - With contents: {:?}\n\ - Without contents: {:?}\n\ - Matching lines:\n\ - {}\n", - with, - without, - matches.join("\n") - )), - } - } - - fn match_json(&self, expected: &str, line: &str) -> MatchResult { - let actual = match line.parse() { - Err(e) => return Err(format!("invalid json, {}:\n`{}`", e, line)), - Ok(actual) => actual, - }; - let expected = match expected.parse() { - Err(e) => return Err(format!("invalid json, {}:\n`{}`", e, line)), - Ok(expected) => expected, - }; - - let cwd = self.process_builder.as_ref().and_then(|p| p.get_cwd()); - find_json_mismatch(&expected, &actual, cwd) - } - - fn diff_lines<'a>( - &self, - actual: str::Lines<'a>, - expected: str::Lines<'a>, - partial: bool, - ) -> Vec { - let actual = actual.take(if partial { - expected.clone().count() - } else { - usize::MAX - }); - zip_all(actual, expected) - .enumerate() - .filter_map(|(i, (a, e))| match (a, e) { - (Some(a), Some(e)) => { - if lines_match(e, a) { - None - } else { - Some(format!("{:3} - |{}|\n + |{}|\n", i, e, a)) - } - } - (Some(a), None) => Some(format!("{:3} -\n + |{}|\n", i, a)), - (None, Some(e)) => Some(format!("{:3} - |{}|\n +\n", i, e)), - (None, None) => panic!("Cannot get here"), - }) - .collect() - } } impl Drop for Execs { @@ -1195,237 +964,6 @@ } } -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -enum MatchKind { - Exact, - Partial, - PartialN(usize), - NotPresent, - Unordered, -} - -/// Compares a line with an expected pattern. -/// - Use `[..]` as a wildcard to match 0 or more characters on the same line -/// (similar to `.*` in a regex). It is non-greedy. -/// - Use `[EXE]` to optionally add `.exe` on Windows (empty string on other -/// platforms). -/// - There is a wide range of macros (such as `[COMPILING]` or `[WARNING]`) -/// to match cargo's "status" output and allows you to ignore the alignment. -/// See `substitute_macros` for a complete list of macros. -/// - `[ROOT]` the path to the test directory's root -/// - `[CWD]` is the working directory of the process that was run. -pub fn lines_match(expected: &str, mut actual: &str) -> bool { - let expected = substitute_macros(expected); - for (i, part) in expected.split("[..]").enumerate() { - match actual.find(part) { - Some(j) => { - if i == 0 && j != 0 { - return false; - } - actual = &actual[j + part.len()..]; - } - None => return false, - } - } - actual.is_empty() || expected.ends_with("[..]") -} - -pub fn lines_match_unordered(expected: &str, actual: &str) -> Result<(), String> { - let mut a = actual.lines().collect::>(); - // match more-constrained lines first, although in theory we'll - // need some sort of recursive match here. This handles the case - // that you expect "a\n[..]b" and two lines are printed out, - // "ab\n"a", where technically we do match unordered but a naive - // search fails to find this. This simple sort at least gets the - // test suite to pass for now, but we may need to get more fancy - // if tests start failing again. - a.sort_by_key(|s| s.len()); - let mut failures = Vec::new(); - - for e_line in expected.lines() { - match a.iter().position(|a_line| lines_match(e_line, a_line)) { - Some(index) => { - a.remove(index); - } - None => failures.push(e_line), - } - } - if !failures.is_empty() { - return Err(format!( - "Did not find expected line(s):\n{}\n\ - Remaining available output:\n{}\n", - failures.join("\n"), - a.join("\n") - )); - } - if !a.is_empty() { - Err(format!( - "Output included extra lines:\n\ - {}\n", - a.join("\n") - )) - } else { - Ok(()) - } -} - -/// Variant of `lines_match` that applies normalization to the strings. -pub fn normalized_lines_match(expected: &str, actual: &str, cwd: Option<&Path>) -> bool { - let expected = normalize_matcher(expected, cwd); - let actual = normalize_matcher(actual, cwd); - lines_match(&expected, &actual) -} - -fn normalize_matcher(matcher: &str, cwd: Option<&Path>) -> String { - // Let's not deal with / vs \ (windows...) - let matcher = matcher.replace("\\\\", "/").replace("\\", "/"); - - // Weirdness for paths on Windows extends beyond `/` vs `\` apparently. - // Namely paths like `c:\` and `C:\` are equivalent and that can cause - // issues. The return value of `env::current_dir()` may return a - // lowercase drive name, but we round-trip a lot of values through `Url` - // which will auto-uppercase the drive name. To just ignore this - // distinction we try to canonicalize as much as possible, taking all - // forms of a path and canonicalizing them to one. - let replace_path = |s: &str, path: &Path, with: &str| { - let path_through_url = Url::from_file_path(path).unwrap().to_file_path().unwrap(); - let path1 = path.display().to_string().replace("\\", "/"); - let path2 = path_through_url.display().to_string().replace("\\", "/"); - s.replace(&path1, with) - .replace(&path2, with) - .replace(with, &path1) - }; - - // Do the template replacements on the expected string. - let matcher = match cwd { - None => matcher, - Some(p) => replace_path(&matcher, p, "[CWD]"), - }; - - // Similar to cwd above, perform similar treatment to the root path - // which in theory all of our paths should otherwise get rooted at. - let root = paths::root(); - let matcher = replace_path(&matcher, &root, "[ROOT]"); - - // Let's not deal with \r\n vs \n on windows... - let matcher = matcher.replace("\r", ""); - - // It's easier to read tabs in outputs if they don't show up as literal - // hidden characters - matcher.replace("\t", "") -} - -#[test] -fn lines_match_works() { - assert!(lines_match("a b", "a b")); - assert!(lines_match("a[..]b", "a b")); - assert!(lines_match("a[..]", "a b")); - assert!(lines_match("[..]", "a b")); - assert!(lines_match("[..]b", "a b")); - - assert!(!lines_match("[..]b", "c")); - assert!(!lines_match("b", "c")); - assert!(!lines_match("b", "cb")); -} - -/// Compares JSON object for approximate equality. -/// You can use `[..]` wildcard in strings (useful for OS-dependent things such -/// as paths). You can use a `"{...}"` string literal as a wildcard for -/// arbitrary nested JSON (useful for parts of object emitted by other programs -/// (e.g., rustc) rather than Cargo itself). -pub fn find_json_mismatch( - expected: &Value, - actual: &Value, - cwd: Option<&Path>, -) -> Result<(), String> { - match find_json_mismatch_r(expected, actual, cwd) { - Some((expected_part, actual_part)) => Err(format!( - "JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n", - serde_json::to_string_pretty(expected).unwrap(), - serde_json::to_string_pretty(&actual).unwrap(), - serde_json::to_string_pretty(expected_part).unwrap(), - serde_json::to_string_pretty(actual_part).unwrap(), - )), - None => Ok(()), - } -} - -fn find_json_mismatch_r<'a>( - expected: &'a Value, - actual: &'a Value, - cwd: Option<&Path>, -) -> Option<(&'a Value, &'a Value)> { - use serde_json::Value::*; - match (expected, actual) { - (&Number(ref l), &Number(ref r)) if l == r => None, - (&Bool(l), &Bool(r)) if l == r => None, - (&String(ref l), _) if l == "{...}" => None, - (&String(ref l), &String(ref r)) => { - let normalized = normalize_matcher(r, cwd); - if lines_match(l, &normalized) { - None - } else { - Some((expected, actual)) - } - } - (&Array(ref l), &Array(ref r)) => { - if l.len() != r.len() { - return Some((expected, actual)); - } - - l.iter() - .zip(r.iter()) - .filter_map(|(l, r)| find_json_mismatch_r(l, r, cwd)) - .next() - } - (&Object(ref l), &Object(ref r)) => { - let same_keys = l.len() == r.len() && l.keys().all(|k| r.contains_key(k)); - if !same_keys { - return Some((expected, actual)); - } - - l.values() - .zip(r.values()) - .filter_map(|(l, r)| find_json_mismatch_r(l, r, cwd)) - .next() - } - (&Null, &Null) => None, - // Magic string literal `"{...}"` acts as wildcard for any sub-JSON. - _ => Some((expected, actual)), - } -} - -struct ZipAll { - first: I1, - second: I2, -} - -impl, I2: Iterator> Iterator for ZipAll { - type Item = (Option, Option); - fn next(&mut self) -> Option<(Option, Option)> { - let first = self.first.next(); - let second = self.second.next(); - - match (first, second) { - (None, None) => None, - (a, b) => Some((a, b)), - } - } -} - -fn zip_all, I2: Iterator>(a: I1, b: I2) -> ZipAll { - ZipAll { - first: a, - second: b, - } -} - -impl fmt::Debug for Execs { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "execs") - } -} - pub fn execs() -> Execs { Execs { ran: false, @@ -1436,30 +974,17 @@ expect_exit_code: Some(0), expect_stdout_contains: Vec::new(), expect_stderr_contains: Vec::new(), - expect_either_contains: Vec::new(), expect_stdout_contains_n: Vec::new(), expect_stdout_not_contains: Vec::new(), expect_stderr_not_contains: Vec::new(), expect_stderr_unordered: Vec::new(), - expect_neither_contains: Vec::new(), expect_stderr_with_without: Vec::new(), expect_json: None, - expect_json_contains_unordered: Vec::new(), + expect_json_contains_unordered: None, stream_output: false, } } -pub trait Tap { - fn tap(self, callback: F) -> Self; -} - -impl Tap for T { - fn tap(mut self, callback: F) -> T { - callback(&mut self); - self - } -} - pub fn basic_manifest(name: &str, version: &str) -> String { format!( r#" @@ -1510,56 +1035,6 @@ Url::from_file_path(p).ok().unwrap() } -fn substitute_macros(input: &str) -> String { - let macros = [ - ("[RUNNING]", " Running"), - ("[COMPILING]", " Compiling"), - ("[CHECKING]", " Checking"), - ("[COMPLETED]", " Completed"), - ("[CREATED]", " Created"), - ("[FINISHED]", " Finished"), - ("[ERROR]", "error:"), - ("[WARNING]", "warning:"), - ("[NOTE]", "note:"), - ("[HELP]", "help:"), - ("[DOCUMENTING]", " Documenting"), - ("[FRESH]", " Fresh"), - ("[UPDATING]", " Updating"), - ("[ADDING]", " Adding"), - ("[REMOVING]", " Removing"), - ("[DOCTEST]", " Doc-tests"), - ("[PACKAGING]", " Packaging"), - ("[DOWNLOADING]", " Downloading"), - ("[DOWNLOADED]", " Downloaded"), - ("[UPLOADING]", " Uploading"), - ("[VERIFYING]", " Verifying"), - ("[ARCHIVING]", " Archiving"), - ("[INSTALLING]", " Installing"), - ("[REPLACING]", " Replacing"), - ("[UNPACKING]", " Unpacking"), - ("[SUMMARY]", " Summary"), - ("[FIXED]", " Fixed"), - ("[FIXING]", " Fixing"), - ("[EXE]", env::consts::EXE_SUFFIX), - ("[IGNORED]", " Ignored"), - ("[INSTALLED]", " Installed"), - ("[REPLACED]", " Replaced"), - ("[BUILDING]", " Building"), - ("[LOGIN]", " Login"), - ("[LOGOUT]", " Logout"), - ("[YANK]", " Yank"), - ("[OWNER]", " Owner"), - ("[MIGRATING]", " Migrating"), - ]; - let mut result = input.to_owned(); - for &(pat, subst) in ¯os { - result = result.replace(pat, subst) - } - result -} - -pub mod install; - struct RustcInfo { verbose_version: String, host: String, @@ -1594,6 +1069,11 @@ &RUSTC_INFO.host } +/// The host triple suitable for use in a cargo environment variable (uppercased). +pub fn rustc_host_env() -> String { + rustc_host().to_uppercase().replace('-', "_") +} + pub fn is_nightly() -> bool { let vv = &RUSTC_INFO.verbose_version; env::var("CARGO_TEST_DISABLE_NIGHTLY").is_err() @@ -1618,11 +1098,27 @@ if env::var_os("RUSTUP_TOOLCHAIN").is_some() { // Override the PATH to avoid executing the rustup wrapper thousands // of times. This makes the testsuite run substantially faster. + lazy_static::lazy_static! { + static ref RUSTC_DIR: PathBuf = { + match ProcessBuilder::new("rustup") + .args(&["which", "rustc"]) + .exec_with_output() + { + Ok(output) => { + let s = str::from_utf8(&output.stdout).expect("utf8").trim(); + let mut p = PathBuf::from(s); + p.pop(); + p + } + Err(e) => { + panic!("RUSTUP_TOOLCHAIN was set, but could not run rustup: {}", e); + } + } + }; + } let path = env::var_os("PATH").unwrap_or_default(); let paths = env::split_paths(&path); - let mut outer_cargo = PathBuf::from(env::var_os("CARGO").unwrap()); - outer_cargo.pop(); - let new_path = env::join_paths(std::iter::once(outer_cargo).chain(paths)).unwrap(); + let new_path = env::join_paths(std::iter::once(RUSTC_DIR.clone()).chain(paths)).unwrap(); p.env("PATH", new_path); } diff -Nru cargo-0.54.0/crates/cargo-test-support/src/paths.rs cargo-0.58.0/crates/cargo-test-support/src/paths.rs --- cargo-0.54.0/crates/cargo-test-support/src/paths.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/crates/cargo-test-support/src/paths.rs 2021-10-21 14:30:11.000000000 +0000 @@ -1,4 +1,3 @@ -use crate::{basic_manifest, project}; use filetime::{self, FileTime}; use lazy_static::lazy_static; use std::cell::RefCell; @@ -14,28 +13,44 @@ 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> = Mutex::new(None); static ref TEST_ROOTS: Mutex> = 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 +67,15 @@ _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 +96,10 @@ 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 { @@ -105,8 +124,6 @@ fn move_in_time(&self, travel_amount: F) where F: Fn(i64, u32) -> (i64, u32); - - fn is_symlink(&self) -> bool; } impl CargoPathExt for Path { @@ -179,12 +196,14 @@ }); } } +} - fn is_symlink(&self) -> bool { - fs::symlink_metadata(self) - .map(|m| m.file_type().is_symlink()) - .unwrap_or(false) - } +// Replace with std implementation when stabilized, see +// https://github.com/rust-lang/rust/issues/85748 +pub fn is_symlink(path: &Path) -> bool { + fs::symlink_metadata(path) + .map(|m| m.file_type().is_symlink()) + .unwrap_or(false) } fn do_op(path: &Path, desc: &str, mut f: F) @@ -276,24 +295,3 @@ let sysroot = String::from_utf8(output.stdout).unwrap(); sysroot.trim().to_string() } - -pub fn echo_wrapper() -> std::path::PathBuf { - let p = project() - .at("rustc-echo-wrapper") - .file("Cargo.toml", &basic_manifest("rustc-echo-wrapper", "1.0.0")) - .file( - "src/main.rs", - r#" - fn main() { - let args = std::env::args().collect::>(); - eprintln!("WRAPPER CALLED: {}", args[1..].join(" ")); - let status = std::process::Command::new(&args[1]) - .args(&args[2..]).status().unwrap(); - std::process::exit(status.code().unwrap_or(1)); - } - "#, - ) - .build(); - p.cargo("build").run(); - p.bin("rustc-echo-wrapper") -} diff -Nru cargo-0.54.0/crates/cargo-test-support/src/publish.rs cargo-0.58.0/crates/cargo-test-support/src/publish.rs --- cargo-0.54.0/crates/cargo-test-support/src/publish.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/crates/cargo-test-support/src/publish.rs 2021-10-21 14:30:11.000000000 +0000 @@ -1,5 +1,5 @@ +use crate::compare::{assert_match_exact, find_json_mismatch}; use crate::registry::{self, alt_api_path}; -use crate::{find_json_mismatch, lines_match}; use flate2::read::GzDecoder; use std::collections::{HashMap, HashSet}; use std::fs::File; @@ -151,16 +151,7 @@ let actual_contents = files .get(&full_e_name) .unwrap_or_else(|| panic!("file `{}` missing in archive", e_file_name)); - if !lines_match(e_file_contents, actual_contents) { - panic!( - "Crate contents mismatch for {:?}:\n\ - --- expected\n\ - {}\n\ - --- actual \n\ - {}\n", - e_file_name, e_file_contents, actual_contents - ); - } + assert_match_exact(e_file_contents, actual_contents); } } } diff -Nru cargo-0.54.0/crates/cargo-test-support/src/registry.rs cargo-0.58.0/crates/cargo-test-support/src/registry.rs --- cargo-0.54.0/crates/cargo-test-support/src/registry.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/crates/cargo-test-support/src/registry.rs 2021-10-21 14:30:11.000000000 +0000 @@ -1,6 +1,6 @@ use crate::git::repo; use crate::paths; -use cargo_util::Sha256; +use cargo_util::{registry::make_dep_path, Sha256}; use flate2::write::GzEncoder; use flate2::Compression; use std::collections::BTreeMap; @@ -178,12 +178,7 @@ } 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 { @@ -632,12 +627,7 @@ } let line = json.to_string(); - let file = match self.name.len() { - 1 => format!("1/{}", self.name), - 2 => format!("2/{}", self.name), - 3 => format!("3/{}/{}", &self.name[..1], self.name), - _ => format!("{}/{}/{}", &self.name[0..2], &self.name[2..4], self.name), - }; + let file = make_dep_path(&self.name, false); let registry_path = if self.alternative { alt_registry_path() diff -Nru cargo-0.54.0/crates/cargo-test-support/src/tools.rs cargo-0.58.0/crates/cargo-test-support/src/tools.rs --- cargo-0.54.0/crates/cargo-test-support/src/tools.rs 1970-01-01 00:00:00.000000000 +0000 +++ cargo-0.58.0/crates/cargo-test-support/src/tools.rs 2021-10-21 14:30:11.000000000 +0000 @@ -0,0 +1,99 @@ +//! Common executables that can be reused by various tests. + +use crate::{basic_manifest, paths, project, Project}; +use lazy_static::lazy_static; +use std::path::{Path, PathBuf}; +use std::sync::Mutex; + +lazy_static! { + static ref ECHO_WRAPPER: Mutex> = Mutex::new(None); + static ref ECHO: Mutex> = Mutex::new(None); +} + +/// Returns the path to an executable that works as a wrapper around rustc. +/// +/// The wrapper will echo the command line it was called with to stderr. +pub fn echo_wrapper() -> PathBuf { + let mut lock = ECHO_WRAPPER.lock().unwrap(); + if let Some(path) = &*lock { + return path.clone(); + } + let p = project() + .at(paths::global_root().join("rustc-echo-wrapper")) + .file("Cargo.toml", &basic_manifest("rustc-echo-wrapper", "1.0.0")) + .file( + "src/main.rs", + r#" + fn main() { + let args = std::env::args().collect::>(); + eprintln!("WRAPPER CALLED: {}", args[1..].join(" ")); + let status = std::process::Command::new(&args[1]) + .args(&args[2..]).status().unwrap(); + std::process::exit(status.code().unwrap_or(1)); + } + "#, + ) + .build(); + p.cargo("build").run(); + let path = p.bin("rustc-echo-wrapper"); + *lock = Some(path.clone()); + path +} + +/// Returns the path to an executable that prints its arguments. +/// +/// Do not expect this to be anything fancy. +pub fn echo() -> PathBuf { + let mut lock = ECHO.lock().unwrap(); + if let Some(path) = &*lock { + return path.clone(); + } + if let Ok(path) = cargo_util::paths::resolve_executable(Path::new("echo")) { + *lock = Some(path.clone()); + return path; + } + // Often on Windows, `echo` is not available. + let p = project() + .at(paths::global_root().join("basic-echo")) + .file("Cargo.toml", &basic_manifest("basic-echo", "1.0.0")) + .file( + "src/main.rs", + r#" + fn main() { + let mut s = String::new(); + let mut it = std::env::args().skip(1).peekable(); + while let Some(n) = it.next() { + s.push_str(&n); + if it.peek().is_some() { + s.push(' '); + } + } + println!("{}", s); + } + "#, + ) + .build(); + p.cargo("build").run(); + let path = p.bin("basic-echo"); + *lock = Some(path.clone()); + path +} + +/// Returns a project which builds a cargo-echo simple subcommand +pub fn echo_subcommand() -> Project { + let p = project() + .at("cargo-echo") + .file("Cargo.toml", &basic_manifest("cargo-echo", "0.0.1")) + .file( + "src/main.rs", + r#" + fn main() { + let args: Vec<_> = ::std::env::args().skip(1).collect(); + println!("{}", args.join(" ")); + } + "#, + ) + .build(); + p.cargo("build").run(); + p +} diff -Nru cargo-0.54.0/crates/cargo-util/Cargo.toml cargo-0.58.0/crates/cargo-util/Cargo.toml --- cargo-0.54.0/crates/cargo-util/Cargo.toml 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/crates/cargo-util/Cargo.toml 2021-10-21 14:30:11.000000000 +0000 @@ -1,6 +1,6 @@ [package] name = "cargo-util" -version = "0.1.0" +version = "0.1.1" authors = ["The Cargo Project Developers"] edition = "2018" license = "MIT OR Apache-2.0" diff -Nru cargo-0.54.0/crates/cargo-util/src/lib.rs cargo-0.58.0/crates/cargo-util/src/lib.rs --- cargo-0.54.0/crates/cargo-util/src/lib.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/crates/cargo-util/src/lib.rs 2021-10-21 14:30:11.000000000 +0000 @@ -9,6 +9,7 @@ mod process_builder; mod process_error; mod read2; +pub mod registry; mod sha256; /// Whether or not this running in a Continuous Integration environment. diff -Nru cargo-0.54.0/crates/cargo-util/src/paths.rs cargo-0.58.0/crates/cargo-util/src/paths.rs --- cargo-0.54.0/crates/cargo-util/src/paths.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/crates/cargo-util/src/paths.rs 2021-10-21 14:30:11.000000000 +0000 @@ -161,7 +161,7 @@ .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, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> { (|| -> Result<()> { @@ -184,7 +184,7 @@ 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<()> { @@ -637,6 +637,7 @@ // point as the old one). let tempdir = TempFileBuilder::new().prefix(base).tempdir_in(parent)?; exclude_from_backups(tempdir.path()); + exclude_from_content_indexing(tempdir.path()); // Previously std::fs::create_dir_all() (through paths::create_dir_all()) was used // here to create the directory directly and fs::create_dir_all() explicitly treats // the directory being created concurrently by another thread or process as success, @@ -670,6 +671,35 @@ // Similarly to exclude_from_time_machine() we ignore errors here as it's an optional feature. } +/// Marks the directory as excluded from content indexing. +/// +/// This is recommended to prevent the content of derived/temporary files from being indexed. +/// This is very important for Windows users, as the live content indexing significantly slows +/// cargo's I/O operations. +/// +/// This is currently a no-op on non-Windows platforms. +fn exclude_from_content_indexing(path: &Path) { + #[cfg(windows)] + { + use std::iter::once; + use std::os::windows::prelude::OsStrExt; + use winapi::um::fileapi::{GetFileAttributesW, SetFileAttributesW}; + use winapi::um::winnt::FILE_ATTRIBUTE_NOT_CONTENT_INDEXED; + + let path: Vec = path.as_os_str().encode_wide().chain(once(0)).collect(); + unsafe { + SetFileAttributesW( + path.as_ptr(), + GetFileAttributesW(path.as_ptr()) | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, + ); + } + } + #[cfg(not(windows))] + { + let _ = path; + } +} + #[cfg(not(target_os = "macos"))] fn exclude_from_time_machine(_: &Path) {} diff -Nru cargo-0.54.0/crates/cargo-util/src/process_builder.rs cargo-0.58.0/crates/cargo-util/src/process_builder.rs --- cargo-0.54.0/crates/cargo-util/src/process_builder.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/crates/cargo-util/src/process_builder.rs 2021-10-21 14:30:11.000000000 +0000 @@ -243,47 +243,54 @@ .stdin(Stdio::null()); let mut callback_error = None; + let mut stdout_pos = 0; + let mut stderr_pos = 0; let status = (|| { let mut child = cmd.spawn()?; let out = child.stdout.take().unwrap(); let err = child.stderr.take().unwrap(); read2(out, err, &mut |is_out, data, eof| { + let pos = if is_out { + &mut stdout_pos + } else { + &mut stderr_pos + }; let idx = if eof { data.len() } else { - match data.iter().rposition(|b| *b == b'\n') { - Some(i) => i + 1, - None => return, + match data[*pos..].iter().rposition(|b| *b == b'\n') { + Some(i) => *pos + i + 1, + None => { + *pos = data.len(); + return; + } } }; - { - // scope for new_lines - let new_lines = if capture_output { - let dst = if is_out { &mut stdout } else { &mut stderr }; - let start = dst.len(); - let data = data.drain(..idx); - dst.extend(data); - &dst[start..] + + let new_lines = &data[..idx]; + + for line in String::from_utf8_lossy(new_lines).lines() { + if callback_error.is_some() { + break; + } + let callback_result = if is_out { + on_stdout_line(line) } else { - &data[..idx] + on_stderr_line(line) }; - for line in String::from_utf8_lossy(new_lines).lines() { - if callback_error.is_some() { - break; - } - let callback_result = if is_out { - on_stdout_line(line) - } else { - on_stderr_line(line) - }; - if let Err(e) = callback_result { - callback_error = Some(e); - } + if let Err(e) = callback_result { + callback_error = Some(e); + break; } } - if !capture_output { - data.drain(..idx); + + if capture_output { + let dst = if is_out { &mut stdout } else { &mut stderr }; + dst.extend(new_lines); } + + data.drain(..idx); + *pos = 0; })?; child.wait() })() diff -Nru cargo-0.54.0/crates/cargo-util/src/registry.rs cargo-0.58.0/crates/cargo-util/src/registry.rs --- cargo-0.54.0/crates/cargo-util/src/registry.rs 1970-01-01 00:00:00.000000000 +0000 +++ cargo-0.58.0/crates/cargo-util/src/registry.rs 2021-10-21 14:30:11.000000000 +0000 @@ -0,0 +1,45 @@ +/// Make a path to a dependency, which aligns to +/// +/// - [index from of Cargo's index on filesystem][1], and +/// - [index from Crates.io][2]. +/// +/// [1]: https://docs.rs/cargo/latest/cargo/sources/registry/index.html#the-format-of-the-index +/// [2]: https://github.com/rust-lang/crates.io-index +pub fn make_dep_path(dep_name: &str, prefix_only: bool) -> String { + let (slash, name) = if prefix_only { + ("", "") + } else { + ("/", dep_name) + }; + match dep_name.len() { + 1 => format!("1{}{}", slash, name), + 2 => format!("2{}{}", slash, name), + 3 => format!("3/{}{}{}", &dep_name[..1], slash, name), + _ => format!("{}/{}{}{}", &dep_name[0..2], &dep_name[2..4], slash, name), + } +} + +#[cfg(test)] +mod tests { + use super::make_dep_path; + + #[test] + fn prefix_only() { + assert_eq!(make_dep_path("a", true), "1"); + assert_eq!(make_dep_path("ab", true), "2"); + assert_eq!(make_dep_path("abc", true), "3/a"); + assert_eq!(make_dep_path("Abc", true), "3/A"); + assert_eq!(make_dep_path("AbCd", true), "Ab/Cd"); + assert_eq!(make_dep_path("aBcDe", true), "aB/cD"); + } + + #[test] + fn full() { + assert_eq!(make_dep_path("a", false), "1/a"); + assert_eq!(make_dep_path("ab", false), "2/ab"); + assert_eq!(make_dep_path("abc", false), "3/a/abc"); + assert_eq!(make_dep_path("Abc", false), "3/A/Abc"); + assert_eq!(make_dep_path("AbCd", false), "Ab/Cd/AbCd"); + assert_eq!(make_dep_path("aBcDe", false), "aB/cD/aBcDe"); + } +} diff -Nru cargo-0.54.0/crates/mdman/Cargo.lock cargo-0.58.0/crates/mdman/Cargo.lock --- cargo-0.54.0/crates/mdman/Cargo.lock 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/crates/mdman/Cargo.lock 2021-10-21 14:30:11.000000000 +0000 @@ -92,6 +92,16 @@ 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" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -391,10 +401,11 @@ [[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", diff -Nru cargo-0.54.0/crates/mdman/Cargo.toml cargo-0.58.0/crates/mdman/Cargo.toml --- cargo-0.54.0/crates/mdman/Cargo.toml 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/crates/mdman/Cargo.toml 2021-10-21 14:30:11.000000000 +0000 @@ -12,7 +12,7 @@ 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" diff -Nru cargo-0.54.0/crates/mdman/doc/mdman.md cargo-0.58.0/crates/mdman/doc/mdman.md --- cargo-0.54.0/crates/mdman/doc/mdman.md 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/crates/mdman/doc/mdman.md 2021-10-21 14:30:11.000000000 +0000 @@ -57,11 +57,11 @@ {{#option "`-t` _type_"}} Specifies the output type. The following output types are supported: -- `man` — A troff-style man page. Outputs with a numbered extension (like +- `man` — A troff-style man page. Outputs with a numbered extension (like `.1`) matching the man page section. -- `md` — A markdown file, after all handlebars processing has been finished. +- `md` — A markdown file, after all handlebars processing has been finished. Outputs with the `.md` extension. -- `txt` — A text file, rendered for situations where a man page viewer isn't +- `txt` — A text file, rendered for situations where a man page viewer isn't available. Outputs with the `.txt` extension. {{/option}} diff -Nru cargo-0.54.0/crates/mdman/doc/out/mdman.1 cargo-0.58.0/crates/mdman/doc/out/mdman.1 --- cargo-0.54.0/crates/mdman/doc/out/mdman.1 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/crates/mdman/doc/out/mdman.1 2021-10-21 14:30:11.000000000 +0000 @@ -73,17 +73,17 @@ Specifies the output type. The following output types are supported: .sp .RS 4 -\h'-04'\(bu\h'+02'\fBman\fR \[em]\ A troff\-style man page. Outputs with a numbered extension (like +\h'-04'\(bu\h'+02'\fBman\fR \[em] A troff\-style man page. Outputs with a numbered extension (like \fB\&.1\fR) matching the man page section. .RE .sp .RS 4 -\h'-04'\(bu\h'+02'\fBmd\fR \[em]\ A markdown file, after all handlebars processing has been finished. +\h'-04'\(bu\h'+02'\fBmd\fR \[em] A markdown file, after all handlebars processing has been finished. Outputs with the \fB\&.md\fR extension. .RE .sp .RS 4 -\h'-04'\(bu\h'+02'\fBtxt\fR \[em]\ A text file, rendered for situations where a man page viewer isn't +\h'-04'\(bu\h'+02'\fBtxt\fR \[em] A text file, rendered for situations where a man page viewer isn't available. Outputs with the \fB\&.txt\fR extension. .RE .RE diff -Nru cargo-0.54.0/crates/mdman/doc/out/mdman.md cargo-0.58.0/crates/mdman/doc/out/mdman.md --- cargo-0.54.0/crates/mdman/doc/out/mdman.md 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/crates/mdman/doc/out/mdman.md 2021-10-21 14:30:11.000000000 +0000 @@ -54,36 +54,36 @@
-
-t type
-
Specifies the output type. The following output types are supported:

+
-t type
+
Specifies the output type. The following output types are supported:

    -
  • man — A troff-style man page. Outputs with a numbered extension (like +
  • man — A troff-style man page. Outputs with a numbered extension (like .1) matching the man page section.
  • -
  • md — A markdown file, after all handlebars processing has been finished. +
  • md — A markdown file, after all handlebars processing has been finished. Outputs with the .md extension.
  • -
  • txt — A text file, rendered for situations where a man page viewer isn't +
  • txt — A text file, rendered for situations where a man page viewer isn't available. Outputs with the .txt extension.
-
-o outdir
-
Specifies the directory where to save the output.
+
-o outdir
+
Specifies the directory where to save the output.
-
--url base_url
-
Specifies a base URL to use for relative URLs within the document. Any +
--url base_url
+
Specifies a base URL to use for relative URLs within the document. Any relative URL will be joined with this URL.
-
--man name:section=url
-
Specifies a URL to use for the given man page. When the {{man name section}} expression is used, the given URL will be inserted as a link. This +
--man name:section=url
+
Specifies a URL to use for the given man page. When the {{man name section}} expression is used, the given URL will be inserted as a link. This may be specified multiple times. If a man page reference does not have a matching --man entry, then a relative link to a file named name.md will be used.
-
sources...
-
The source input filename, may be specified multiple times.
+
sources...
+
The source input filename, may be specified multiple times.
diff -Nru cargo-0.54.0/crates/mdman/doc/out/mdman.txt cargo-0.58.0/crates/mdman/doc/out/mdman.txt --- cargo-0.54.0/crates/mdman/doc/out/mdman.txt 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/crates/mdman/doc/out/mdman.txt 2021-10-21 14:30:11.000000000 +0000 @@ -58,13 +58,13 @@ -t type Specifies the output type. The following output types are supported: - o man — A troff-style man page. Outputs with a numbered - extension (like .1) matching the man page section. + o man — A troff-style man page. Outputs with a numbered extension + (like .1) matching the man page section. - o md — A markdown file, after all handlebars processing has been + o md — A markdown file, after all handlebars processing has been finished. Outputs with the .md extension. - o txt — A text file, rendered for situations where a man page + o txt — A text file, rendered for situations where a man page viewer isn't available. Outputs with the .txt extension. -o outdir diff -Nru cargo-0.54.0/crates/mdman/src/lib.rs cargo-0.58.0/crates/mdman/src/lib.rs --- cargo-0.54.0/crates/mdman/src/lib.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/crates/mdman/src/lib.rs 2021-10-21 14:30:11.000000000 +0000 @@ -96,7 +96,7 @@ 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, diff -Nru cargo-0.54.0/crates/resolver-tests/src/lib.rs cargo-0.58.0/crates/resolver-tests/src/lib.rs --- cargo-0.54.0/crates/resolver-tests/src/lib.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/crates/resolver-tests/src/lib.rs 2021-10-21 14:30:11.000000000 +0000 @@ -10,7 +10,7 @@ use std::time::Instant; use cargo::core::dependency::DepKind; -use cargo::core::resolver::{self, ResolveOpts}; +use cargo::core::resolver::{self, ResolveOpts, VersionPreferences}; use cargo::core::source::{GitReference, SourceId}; use cargo::core::Resolve; use cargo::core::{Dependency, PackageId, Registry, Summary}; @@ -183,7 +183,7 @@ &[(summary, opts)], &[], &mut registry, - &HashSet::new(), + &VersionPreferences::default(), Some(config), true, ); @@ -506,7 +506,7 @@ impl ToDep for &'static str { fn to_dep(self) -> Dependency { - Dependency::parse_no_deprecated(self, Some("1.0.0"), registry_loc()).unwrap() + Dependency::parse(self, Some("1.0.0"), registry_loc()).unwrap() } } @@ -626,7 +626,7 @@ dep_req(name, "*") } pub fn dep_req(name: &str, req: &str) -> Dependency { - Dependency::parse_no_deprecated(name, Some(req), registry_loc()).unwrap() + Dependency::parse(name, Some(req), registry_loc()).unwrap() } pub fn dep_req_kind(name: &str, req: &str, kind: DepKind, public: bool) -> Dependency { let mut dep = dep_req(name, req); @@ -639,7 +639,7 @@ let url = location.into_url().unwrap(); let master = GitReference::Branch("master".to_string()); let source_id = SourceId::for_git(&url, master).unwrap(); - Dependency::parse_no_deprecated(name, Some("1.0.0"), source_id).unwrap() + Dependency::parse(name, Some("1.0.0"), source_id).unwrap() } pub fn dep_kind(name: &str, kind: DepKind) -> Dependency { dep(name).set_kind(kind).clone() diff -Nru cargo-0.54.0/crates/resolver-tests/tests/resolve.rs cargo-0.58.0/crates/resolver-tests/tests/resolve.rs --- cargo-0.54.0/crates/resolver-tests/tests/resolve.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/crates/resolver-tests/tests/resolve.rs 2021-10-21 14:30:11.000000000 +0000 @@ -93,7 +93,7 @@ prop_assert_eq!( res.is_ok(), mres.is_ok(), - "minimal-versions and regular resolver disagree about weather `{} = \"={}\"` can resolve", + "minimal-versions and regular resolver disagree about whether `{} = \"={}\"` can resolve", this.name(), this.version() ) @@ -1498,7 +1498,7 @@ assert_eq!("\ cyclic package dependency: package `A v0.0.0 (registry `https://example.com/`)` depends on itself. Cycle: package `A v0.0.0 (registry `https://example.com/`)` - ... which is depended on by `C v0.0.0 (registry `https://example.com/`)` - ... which is depended on by `A v0.0.0 (registry `https://example.com/`)`\ + ... which satisfies dependency `A = \"*\"` of package `C v0.0.0 (registry `https://example.com/`)` + ... which satisfies dependency `C = \"*\"` of package `A v0.0.0 (registry `https://example.com/`)`\ ", error.to_string()); } diff -Nru cargo-0.54.0/debian/changelog cargo-0.58.0/debian/changelog --- cargo-0.54.0/debian/changelog 2021-10-29 11:10:14.000000000 +0000 +++ cargo-0.58.0/debian/changelog 2022-01-25 06:45:23.000000000 +0000 @@ -1,11 +1,50 @@ -cargo (0.54.0-0ubuntu1~20.04.1) focal; urgency=medium +cargo (0.58.0-0ubuntu1~20.04.1) focal; urgency=medium - [ Michael Hudson-Doyle ] - * Backport to Focal. (LP: #1943842) - * Drop change to -march on armhf. - * Disable the lto::doctest on i386 too. + * Backport to Focal. (LP: #1952104) - -- Olivier Tilloy Fri, 29 Oct 2021 13:10:14 +0200 + -- Michael Hudson-Doyle Tue, 25 Jan 2022 19:45:23 +1300 + +cargo (0.58.0-0ubuntu1) jammy; urgency=medium + + * New upstream version. (LP: #1952104) + * d/patches/2110-use-mfpu-on-armhf.patch: delete, fixed upstream. + * d/patches/filetime-pr-75.patch: Backport fix from filetime crate to + fix ftbfs on s390x. + * d/patches/libc-pr-2642.patch: Partially backport upstream PR to fix + another ftbfs on s390x. + + -- Michael Hudson-Doyle Tue, 25 Jan 2022 14:06:06 +1300 + +cargo (0.57.0+ubuntu-0ubuntu1) jammy; urgency=medium + + * Merge from Debian unstable (LP: #1952104). + * Drop all Ubuntu delta, but repack vendor tarball from Debian to contain a + pristine copy of the libgit2-sys crate, including the bundled libgit2 + source. + * d/patches/2001-Revert-add-bindings-for-git_branch_name_is_valid-715.patch, + d/patches/2002-Revert-Bump-libgit2-submodule-to-1.2.0-744.patch: Remove. + * d/control: Drop libgit2-dev and libhttp-parser-dev from Build-Depends. + + -- Michael Hudson-Doyle Thu, 16 Dec 2021 10:39:46 +1300 + +cargo (0.57.0-3) unstable; urgency=medium + + * Actually fix failing tests. + * Fix armhf build by backporting a rust-cc patch. + + -- Ximin Luo Sun, 24 Oct 2021 14:11:00 +0100 + +cargo (0.57.0-2) unstable; urgency=medium + + * Fix failing tests. + + -- Ximin Luo Sun, 24 Oct 2021 13:13:07 +0100 + +cargo (0.57.0-1) unstable; urgency=medium + + * New upstream release for rustc 1.56.0, 2021 Edition. + + -- Ximin Luo Sun, 24 Oct 2021 01:59:08 +0100 cargo (0.54.0-0ubuntu1) UNRELEASED; urgency=medium diff -Nru cargo-0.54.0/debian/control cargo-0.58.0/debian/control --- cargo-0.54.0/debian/control 2021-10-29 11:10:07.000000000 +0000 +++ cargo-0.58.0/debian/control 2022-01-25 06:45:14.000000000 +0000 @@ -8,21 +8,21 @@ Vasudev Kamath Priority: optional # :native annotations are to support cross-compiling, see README.Debian of rustc -Build-Depends: debhelper (>= 12~), - dpkg-dev (>= 1.17.14), - cargo:native (>= 0.17.0), - rustc:native (>= 1.16), - libstd-rust-dev (>= 1.16), - pkg-config, - cmake, - bash-completion, - python3:native, - libcurl4-gnutls-dev | libcurl4-openssl-dev, - libssh2-1-dev, - libhttp-parser-dev, - libssl-dev, - zlib1g-dev, - git +Build-Depends: + debhelper (>= 12~), + dpkg-dev (>= 1.17.14), + cargo:native (>= 0.17.0), + rustc:native (>= 1.16), + libstd-rust-dev (>= 1.16), + pkg-config, + cmake, + bash-completion, + python3:native, + libcurl4-gnutls-dev | libcurl4-openssl-dev, + libssh2-1-dev, + libssl-dev, + zlib1g-dev, + git Homepage: https://crates.io/ Standards-Version: 4.2.1 Vcs-Git: https://salsa.debian.org/rust-team/cargo.git diff -Nru cargo-0.54.0/debian/copyright cargo-0.58.0/debian/copyright --- cargo-0.54.0/debian/copyright 2021-10-28 19:57:51.000000000 +0000 +++ cargo-0.58.0/debian/copyright 2021-12-20 10:27:19.000000000 +0000 @@ -7,6 +7,7 @@ src/* tests/* .* + build.rs Cargo.* LICENSE-* README.* @@ -53,6 +54,7 @@ vendor/backtrace-sys/* vendor/cc/* vendor/cfg-if/* + vendor/cfg-if-0*/* vendor/filetime/* vendor/fnv/* vendor/git2/* @@ -147,6 +149,17 @@ License: Zlib Comment: see https://github.com/remram44/adler32-rs +Files: + vendor/arrayvec/* + vendor/either/* + vendor/itertools/* +Copyright: 2014-2021 bluss +License: MIT or Apache-2.0 +Comment: + see https://github.com/bluss/arrayvec + see https://github.com/bluss/either + see https://github.com/rust-itertools/itertools + Files: vendor/bitmaps/* Copyright: 2019-2020 Bodil Stokke License: MPL-2.0+ @@ -371,6 +384,11 @@ License: MIT or Apache-2.0 Comment: see https://gitlab.com/mmstick/numtoa +Files: vendor/once_cell/* +Copyright: 2018-2021 Aleksey Kladov +License: MIT OR Apache-2.0 +Comment: see https://github.com/matklad/once_cell + Files: vendor/opener/* Copyright: 2018 Brian Bowman License: MIT or Apache-2.0 @@ -413,6 +431,11 @@ Copyright: 2017, Redox OS Developers License: MIT +Files: vendor/regex-automata/* +Copyright: 2018-2021 Andrew Gallant +License: Unlicense or MIT +Comment: see https://github.com/BurntSushi/regex-automata + Files: vendor/remove_dir_all/* Copyright: 2017, Aaron Power License: MIT or Apache-2.0 @@ -506,6 +529,11 @@ License: Zlib OR Apache-2.0 OR MIT Comment: see https://github.com/Lokathor/tinyvec +Files: vendor/tinyvec_macros/* +Copyright: 2020-2020 Soveu +License: MIT OR Apache-2.0 OR Zlib +Comment: see https://github.com/Soveu/tinyvec_macros + Files: vendor/typenum/* Copyright: 2015-2018 Paho Lurie-Gregg 2015-2018 Andre Bogus @@ -534,14 +562,17 @@ Comment: see https://github.com/reem/ Files: + vendor/form_urlencoded/* vendor/url/* vendor/url_serde/* vendor/percent-encoding/* -Copyright: 2015-2016 Simon Sapin - 2013-2019 The rust-url developers +Copyright: + 2015-2016 Simon Sapin + 2013-2021 The rust-url developers License: MIT or Apache-2.0 -Comment: see https://github.com/servo/rust-url - see https://github.com/servo/rust-url/tree/master/percent_encoding +Comment: + see https://github.com/servo/rust-url + see https://github.com/servo/rust-url/tree/master/percent_encoding Files: vendor/utf8parse/* Copyright: 2016-2019 Joe Wilm @@ -563,6 +594,11 @@ License: Apache-2.0 or MIT Comment: see https://github.com/jwilm/vte +Files: vendor/vte_generate_state_changes/* +Copyright: 2016-2021 Christian Duerr +License: Apache-2.0 OR MIT +Comment: see https://github.com/jwilm/vte + Files: vendor/winapi/* Copyright: 2014-2017 Peter Atashian diff -Nru cargo-0.54.0/debian/debcargo-conf.patch cargo-0.58.0/debian/debcargo-conf.patch --- cargo-0.54.0/debian/debcargo-conf.patch 2021-10-28 19:57:51.000000000 +0000 +++ cargo-0.58.0/debian/debcargo-conf.patch 2021-12-20 10:27:19.000000000 +0000 @@ -1,5 +1,16 @@ -diff --git a/src/commoncrypto-sys/debian/patches/no-clippy.patch b/src/commoncrypto-sys/debian/patches/no-clippy.patch -index 3e4c885..93789f3 100644 +For various reasons sometimes the debcargo-conf patches can't be applied as-is, +so we further patch them here. The reasons are as follows: + +- commoncrypto, commoncrypto-sys: these crates were released before crates.io + automatically re-wrote all Cargo.toml files. cargo-vendor outputs the + un-re-written original Cargo.toml files, but debcargo will forcibly rewrite + even un-re-written ones that were published to crates.io. The patch below + rewrites our existing patches so they work against the un-re-written ones. + +- our patch to miniz_oxide replaces the adler dep for the adler32 dep. This + interferes with our primitive logic in debian-cargo-vendor, so we have to + undo that here. + --- a/src/commoncrypto-sys/debian/patches/no-clippy.patch +++ b/src/commoncrypto-sys/debian/patches/no-clippy.patch @@ -1,17 +1,16 @@ @@ -31,8 +42,6 @@ +- + [dev-dependencies] + hex = "0.2" -diff --git a/src/commoncrypto/debian/patches/no-clippy.patch b/src/commoncrypto/debian/patches/no-clippy.patch -index 38d9c92..b21a7ca 100644 --- a/src/commoncrypto/debian/patches/no-clippy.patch +++ b/src/commoncrypto/debian/patches/no-clippy.patch @@ -1,17 +1,16 @@ @@ -64,35 +73,9 @@ +- + [dev-dependencies] + hex = "0.2" -diff --git a/src/unicode-bidi/debian/patches/no-flamegraphs.patch b/src/unicode-bidi/debian/patches/no-flamegraphs.patch -index 6234d5d..9acab86 100644 ---- a/src/unicode-bidi/debian/patches/no-flamegraphs.patch -+++ b/src/unicode-bidi/debian/patches/no-flamegraphs.patch -@@ -1,5 +1,5 @@ ----- a/Cargo.toml 2017-07-06 23:45:07.000000000 +0000 --+++ b/Cargo.toml 2018-09-15 18:09:13.913086470 +0000 -+--- a/Cargo.toml -++++ b/Cargo.toml - @@ -23,13 +23,6 @@ - - [lib] -@@ -12,12 +12,13 @@ - -version = "0.1" - -optional = true - -- [dependencies.matches] -- version = "0.1" --@@ -44,6 +37,5 @@ -+ [dependencies.serde] -+ version = ">=0.8, <2.0" -+@@ -43,7 +36,6 @@ -+ - [features] -- bench_it = [] -- default = [] -+ with_serde = ["serde"] - -flame_it = ["flame", "flamer"] - unstable = [] -- with_serde = ["serde"] -+ default = [] -+ bench_it = [] +--- a/src/miniz_oxide/debian/patches/series ++++ b/src/miniz_oxide/debian/patches/series +@@ -1,3 +1,2 @@ + remove-rustc-dep-of-std-etc.patch + remove-compiler-builtins.patch +-use-adler32.patch diff -Nru cargo-0.54.0/debian/lintian-to-copyright.sh cargo-0.58.0/debian/lintian-to-copyright.sh --- cargo-0.54.0/debian/lintian-to-copyright.sh 1970-01-01 00:00:00.000000000 +0000 +++ cargo-0.58.0/debian/lintian-to-copyright.sh 2021-12-20 10:27:19.000000000 +0000 @@ -0,0 +1,5 @@ +#!/bin/sh +# Pipe the output of lintian into this. +sed -ne 's,.* file-without-copyright-information debian/copyright ,,p' | cut -d/ -f1-2 | sort -u | while read x; do + /usr/share/cargo/scripts/guess-crate-copyright "$x" +done diff -Nru cargo-0.54.0/debian/make_orig_multi-pre-vendor.sh cargo-0.58.0/debian/make_orig_multi-pre-vendor.sh --- cargo-0.54.0/debian/make_orig_multi-pre-vendor.sh 1970-01-01 00:00:00.000000000 +0000 +++ cargo-0.58.0/debian/make_orig_multi-pre-vendor.sh 2022-01-21 01:59:18.000000000 +0000 @@ -0,0 +1,35 @@ +#!/bin/sh +# Sometimes, by the time we get around to packaging cargo, the crates.io +# ecosystem has moved on from the versions that cargo-vendor *would have* used +# when that version of cargo was released. This places a lot of maintenance +# burden on us, since it requires us to keep debcargo-conf always up-to-date. +# +# This script allows us to force cargo-vendor to use old versions of dependency +# crates, that better match our debcargo-conf patches, as well as the versions +# of crates used when a particular version of cargo was actually released. +# +# Example: +# cargo update -p filetime --precise 0.2.12 +# + +# Drop the "vendored" feature since we patch it out of debcargo +sed -i /vendored/d Cargo.toml + +# For cargo 0.58.0 / rustc 1.57.0 +cargo update -p tempfile --precise 3.2.0 +cargo update -p filetime --precise 0.2.15 +cargo update -p regex --precise 1.5.4 +cargo update -p git2 --precise 0.13.23 +cargo update -p libgit2-sys --precise 0.12.24+1.3.0 +cargo update -p commoncrypto --precise "0.2.0" +cargo update -p commoncrypto-sys --precise "0.2.0" +cargo update -p curl --precise "0.4.39" +cargo update -p curl-sys --precise "0.4.49+curl-7.79.1" +cargo update -p getrandom --precise "0.2.0" +cargo update -p num_cpus --precise "1.13.0" +cargo update -p openssl-sys --precise "0.9.65" +cargo update -p rand --precise "0.8.4" +cargo update -p redox_syscall --precise "0.2.10" +cargo update -p syn --precise "1.0.77" +cargo update -p tar --precise "0.4.37" +cargo update -p tempfile --precise "3.2.0" diff -Nru cargo-0.54.0/debian/make_orig_multi.sh cargo-0.58.0/debian/make_orig_multi.sh --- cargo-0.54.0/debian/make_orig_multi.sh 2021-10-28 19:57:51.000000000 +0000 +++ cargo-0.58.0/debian/make_orig_multi.sh 2021-12-20 10:27:19.000000000 +0000 @@ -1,8 +1,7 @@ #!/bin/sh set -e -echo "" -echo "This needs a local copy of cargo-vendor, and the following packages:" -echo "devscripts" +echo "This needs the following packages:" +echo " python3-pytoml devscripts cargo" echo "" TMPDIR=`mktemp -d` @@ -41,14 +40,17 @@ export GIT_COMMITTER_NAME="${GIT_AUTHOR_NAME}" export GIT_COMMITTER_EMAIL="${GIT_AUTHOR_EMAIL}" -SRCDIR="$SRCDIR" "$SRCDIR/debian/scripts/debian-cargo-vendor" +SRCDIR="$SRCDIR" \ +CARGO_PRE_VENDOR="$SRCDIR/debian/make_orig_multi-pre-vendor.sh" \ +"$SRCDIR/debian/scripts/debian-cargo-vendor" cp -R vendor vendor-scan ( cd vendor-scan "$SRCDIR/debian/scripts/audit-vendor-source" \ "$VENDOR_SUS_WHITELIST" \ - "the 'excludes' key of the relevant debcargo.toml in debcargo-conf.git" + "the 'excludes' key of the relevant debcargo.toml in debcargo-conf.git" \ + -m text/x-script.python ) rm -rf vendor-scan diff -Nru cargo-0.54.0/debian/patches/0001-Update-tar-dependency-to-0.4.34.patch cargo-0.58.0/debian/patches/0001-Update-tar-dependency-to-0.4.34.patch --- cargo-0.54.0/debian/patches/0001-Update-tar-dependency-to-0.4.34.patch 2021-10-28 19:57:51.000000000 +0000 +++ cargo-0.58.0/debian/patches/0001-Update-tar-dependency-to-0.4.34.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -From a02b6e5bfc56fb59d36ac865cd4b3ee4c3b5b54a Mon Sep 17 00:00:00 2001 -From: Alex Crichton -Date: Thu, 27 May 2021 12:48:31 -0700 -Subject: [PATCH] Update tar dependency to 0.4.34 - -Pulls in a fix which should avoid 0 mtime files from showing up. - -Closes #9512 ---- - Cargo.toml | 2 +- - src/cargo/ops/cargo_package.rs | 2 ++ - tests/testsuite/package.rs | 3 ++- - 3 files changed, 5 insertions(+), 2 deletions(-) - ---- a/Cargo.toml -+++ b/Cargo.toml -@@ -56,7 +56,7 @@ - serde_json = { version = "1.0.30", features = ["raw_value"] } - shell-escape = "0.1.4" - strip-ansi-escapes = "0.1.0" --tar = { version = "0.4.26", default-features = false } -+tar = { version = "0.4.35", default-features = false } - tempfile = "3.0" - termcolor = "1.1" - toml = "0.5.7" ---- a/src/cargo/ops/cargo_package.rs -+++ b/src/cargo/ops/cargo_package.rs -@@ -524,6 +524,8 @@ - header.set_entry_type(EntryType::file()); - header.set_mode(0o644); - header.set_size(contents.len() as u64); -+ // use something nonzero to avoid rust-lang/cargo#9512 -+ header.set_mtime(1); - header.set_cksum(); - ar.append_data(&mut header, &ar_path, contents.as_bytes()) - .with_context(|| format!("could not archive source file `{}`", rel_str))?; ---- a/tests/testsuite/package.rs -+++ b/tests/testsuite/package.rs -@@ -1947,9 +1947,10 @@ - let mut archive = Archive::new(decoder); - for ent in archive.entries().unwrap() { - let ent = ent.unwrap(); -+ println!("checking {:?}", ent.path()); - let header = ent.header(); - assert_eq!(header.mode().unwrap(), 0o644); -- assert_eq!(header.mtime().unwrap(), 0); -+ assert!(header.mtime().unwrap() != 0); - assert_eq!(header.username().unwrap().unwrap(), ""); - assert_eq!(header.groupname().unwrap().unwrap(), ""); - } diff -Nru cargo-0.54.0/debian/patches/2002_disable-net-tests.patch cargo-0.58.0/debian/patches/2002_disable-net-tests.patch --- cargo-0.54.0/debian/patches/2002_disable-net-tests.patch 2021-10-28 19:57:51.000000000 +0000 +++ cargo-0.58.0/debian/patches/2002_disable-net-tests.patch 2021-12-20 10:27:19.000000000 +0000 @@ -43,3 +43,14 @@ fn net_retry_git_outputs_warning() { let p = project() .file( +--- a/tests/testsuite/publish.rs ++++ b/tests/testsuite/publish.rs +@@ -1642,7 +1642,7 @@ + t.join().unwrap(); + } + +-#[cargo_test] ++#[allow(dead_code)] + fn api_curl_error() { + // Registry has a network error. + let t = registry::RegistryBuilder::new().build_api_server(&|_headers| panic!("broke!")); diff -Nru cargo-0.54.0/debian/patches/2003_disable_close_output.patch cargo-0.58.0/debian/patches/2003_disable_close_output.patch --- cargo-0.54.0/debian/patches/2003_disable_close_output.patch 2021-10-28 19:57:51.000000000 +0000 +++ cargo-0.58.0/debian/patches/2003_disable_close_output.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -Description: - Disable close_output, it is flaky. - . - It is already fixed upstream in #8587 and #8668, however these depend on - subsequent changes to the same file and is hard to backport. So just disable - it for now in Debian, it is a test problem not a cargo problem. - . - FIXME remove this patch in cargo 0.49 which contains those above FRs. ---- a/tests/testsuite/build.rs -+++ b/tests/testsuite/build.rs -@@ -5133,8 +5133,8 @@ - p.process(&p.bin("foo")).run(); - } - --#[cargo_test] --fn close_output() { -+#[allow(dead_code)] -+fn _close_output() { - // What happens when stdout or stderr is closed during a build. - - // Server to know when rustc has spawned. diff -Nru cargo-0.54.0/debian/patches/2111-curl-no-rebuild.patch cargo-0.58.0/debian/patches/2111-curl-no-rebuild.patch --- cargo-0.54.0/debian/patches/2111-curl-no-rebuild.patch 1970-01-01 00:00:00.000000000 +0000 +++ cargo-0.58.0/debian/patches/2111-curl-no-rebuild.patch 2021-12-20 10:27:19.000000000 +0000 @@ -0,0 +1,12 @@ +Already in debcargo-conf.git, can be deleted for next source import. + +--- a/vendor/curl-sys/build.rs ++++ b/vendor/curl-sys/build.rs +@@ -4,7 +4,6 @@ + use std::process::Command; + + fn main() { +- println!("cargo:rerun-if-changed=curl"); + let host = env::var("HOST").unwrap(); + let target = env::var("TARGET").unwrap(); + let windows = target.contains("windows"); diff -Nru cargo-0.54.0/debian/patches/2112-handle-4-siphasher-algorithms.patch cargo-0.58.0/debian/patches/2112-handle-4-siphasher-algorithms.patch --- cargo-0.54.0/debian/patches/2112-handle-4-siphasher-algorithms.patch 2021-10-28 19:58:51.000000000 +0000 +++ cargo-0.58.0/debian/patches/2112-handle-4-siphasher-algorithms.patch 2021-12-20 10:27:19.000000000 +0000 @@ -2,7 +2,7 @@ --- a/src/cargo/core/source/source_id.rs +++ b/src/cargo/core/source/source_id.rs -@@ -584,7 +584,13 @@ +@@ -621,7 +621,13 @@ fn test_cratesio_hash() { let config = Config::default().unwrap(); let crates_io = SourceId::crates_io(&config).unwrap(); diff -Nru cargo-0.54.0/debian/patches/disable-lto-doctest.patch cargo-0.58.0/debian/patches/disable-lto-doctest.patch --- cargo-0.54.0/debian/patches/disable-lto-doctest.patch 2021-10-28 19:58:51.000000000 +0000 +++ cargo-0.58.0/debian/patches/disable-lto-doctest.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ ---- a/tests/testsuite/lto.rs -+++ b/tests/testsuite/lto.rs -@@ -695,6 +695,7 @@ - } - - #[cargo_test] -+#[cfg(not(target_arch = "x86"))] - fn doctest() { - let p = project() - .file( diff -Nru cargo-0.54.0/debian/patches/disable-lto-test_profiele.patch cargo-0.58.0/debian/patches/disable-lto-test_profiele.patch --- cargo-0.54.0/debian/patches/disable-lto-test_profiele.patch 2021-10-28 19:57:51.000000000 +0000 +++ cargo-0.58.0/debian/patches/disable-lto-test_profiele.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ ---- a/tests/testsuite/lto.rs -+++ b/tests/testsuite/lto.rs -@@ -589,6 +589,7 @@ - } - - #[cargo_test] -+#[cfg(not(target_arch = "x86"))] - fn test_profile() { - Package::new("bar", "0.0.1") - .file("src/lib.rs", "pub fn foo() -> i32 { 123 } ") diff -Nru cargo-0.54.0/debian/patches/filetime-pr-75.patch cargo-0.58.0/debian/patches/filetime-pr-75.patch --- cargo-0.54.0/debian/patches/filetime-pr-75.patch 1970-01-01 00:00:00.000000000 +0000 +++ cargo-0.58.0/debian/patches/filetime-pr-75.patch 2022-01-24 21:24:43.000000000 +0000 @@ -0,0 +1,92 @@ +From 4bf69e074b288cd99965884c4501aa198efe9e3c Mon Sep 17 00:00:00 2001 +From: Alain Zscheile +Date: Mon, 13 Dec 2021 16:34:28 +0100 +Subject: [PATCH] mark some functions as `const fn`, and some fix compiler + warnings (#75) + +* mark fixed init functions and getters as const + +* fix compiler warnings +--- + src/lib.rs | 14 +++++++------- + src/unix/utimes.rs | 1 + + 2 files changed, 8 insertions(+), 7 deletions(-) + +diff --git a/vendor/filetime/src/lib.rs b/vendor/filetime/src/lib.rs +index e29050e..817915c 100644 +--- a/vendor/filetime/src/lib.rs ++++ b/vendor/filetime/src/lib.rs +@@ -71,14 +71,14 @@ impl FileTime { + /// Creates a new timestamp representing a 0 time. + /// + /// Useful for creating the base of a cmp::max chain of times. +- pub fn zero() -> FileTime { ++ pub const fn zero() -> FileTime { + FileTime { + seconds: 0, + nanos: 0, + } + } + +- fn emulate_second_only_system(self) -> FileTime { ++ const fn emulate_second_only_system(self) -> FileTime { + if cfg!(emulate_second_only_system) { + FileTime { + seconds: self.seconds, +@@ -118,7 +118,7 @@ impl FileTime { + /// from, but on Windows the native time stamp is relative to January 1, + /// 1601 so the return value of `seconds` from the returned `FileTime` + /// instance may not be the same as that passed in. +- pub fn from_unix_time(seconds: i64, nanos: u32) -> FileTime { ++ pub const fn from_unix_time(seconds: i64, nanos: u32) -> FileTime { + FileTime { + seconds: seconds + if cfg!(windows) { 11644473600 } else { 0 }, + nanos, +@@ -193,7 +193,7 @@ impl FileTime { + /// Note that this value's meaning is **platform specific**. On Unix + /// platform time stamps are typically relative to January 1, 1970, but on + /// Windows platforms time stamps are relative to January 1, 1601. +- pub fn seconds(&self) -> i64 { ++ pub const fn seconds(&self) -> i64 { + self.seconds + } + +@@ -202,7 +202,7 @@ impl FileTime { + /// + /// Note that this does not return the same value as `seconds` for Windows + /// platforms as seconds are relative to a different date there. +- pub fn unix_seconds(&self) -> i64 { ++ pub const fn unix_seconds(&self) -> i64 { + self.seconds - if cfg!(windows) { 11644473600 } else { 0 } + } + +@@ -211,7 +211,7 @@ impl FileTime { + /// The returned value is always less than one billion and represents a + /// portion of a second forward from the seconds returned by the `seconds` + /// method. +- pub fn nanoseconds(&self) -> u32 { ++ pub const fn nanoseconds(&self) -> u32 { + self.nanos + } + } +@@ -630,7 +630,7 @@ mod tests { + fn set_symlink_dir_times_test() { + let td = Builder::new().prefix("filetime").tempdir().unwrap(); + let path = td.path().join("foo"); +- fs::create_dir(&path); ++ fs::create_dir(&path).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + let mtime = FileTime::from_last_modification_time(&metadata); +diff --git a/vendor/filetime/src/unix/utimes.rs b/vendor/filetime/src/unix/utimes.rs +index 9926921..34bb882 100644 +--- a/vendor/filetime/src/unix/utimes.rs ++++ b/vendor/filetime/src/unix/utimes.rs +@@ -118,6 +118,7 @@ fn to_timeval(ft: &FileTime) -> libc::timeval { + } + } + ++#[cfg(target_env = "uclibc")] + fn to_timespec(ft: &FileTime) -> libc::timespec { + libc::timespec { + tv_sec: ft.seconds() as libc::time_t, diff -Nru cargo-0.54.0/debian/patches/libc-pr-2642.patch cargo-0.58.0/debian/patches/libc-pr-2642.patch --- cargo-0.54.0/debian/patches/libc-pr-2642.patch 1970-01-01 00:00:00.000000000 +0000 +++ cargo-0.58.0/debian/patches/libc-pr-2642.patch 2022-01-24 22:18:20.000000000 +0000 @@ -0,0 +1,147 @@ +From da84eefd712167bac47c904de3ac6056521c7f18 Mon Sep 17 00:00:00 2001 +From: Tamir Duberstein +Date: Sat, 22 Jan 2022 08:13:30 -0500 +Subject: [PATCH] Define ip_mreqn on all Linux platforms + +Updates #1558. +--- + libc-test/build.rs | 5 +++++ + libc-test/semver/linux-aarch64.txt | 1 - + libc-test/semver/linux-i686.txt | 1 - + libc-test/semver/linux-mips.txt | 1 - + libc-test/semver/linux-powerpc.txt | 1 - + libc-test/semver/linux-powerpc64.txt | 1 - + libc-test/semver/linux-powerpc64le.txt | 1 - + libc-test/semver/linux-riscv64gc.txt | 1 - + libc-test/semver/linux-x86_64.txt | 1 - + libc-test/semver/linux.txt | 1 + + src/unix/linux_like/android/mod.rs | 6 ------ + src/unix/linux_like/linux/gnu/b32/mod.rs | 6 ------ + src/unix/linux_like/linux/gnu/b64/aarch64/mod.rs | 6 ------ + src/unix/linux_like/linux/gnu/b64/powerpc64/mod.rs | 6 ------ + src/unix/linux_like/linux/gnu/b64/riscv64/mod.rs | 6 ------ + src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs | 6 ------ + src/unix/linux_like/linux/musl/mod.rs | 6 ------ + src/unix/linux_like/mod.rs | 6 ++++++ + 18 files changed, 12 insertions(+), 50 deletions(-) + +--- a/vendor/libc/src/unix/linux_like/android/mod.rs ++++ b/vendor/libc/src/unix/linux_like/android/mod.rs +@@ -73,12 +73,6 @@ + pub cmsg_type: ::c_int, + } + +- pub struct ip_mreqn { +- pub imr_multiaddr: ::in_addr, +- pub imr_address: ::in_addr, +- pub imr_ifindex: ::c_int, +- } +- + pub struct termios { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, +--- a/vendor/libc/src/unix/linux_like/linux/gnu/b32/mod.rs ++++ b/vendor/libc/src/unix/linux_like/linux/gnu/b32/mod.rs +@@ -135,12 +135,6 @@ + pub _f: [::c_char; 8], + } + +- pub struct ip_mreqn { +- pub imr_multiaddr: ::in_addr, +- pub imr_address: ::in_addr, +- pub imr_ifindex: ::c_int, +- } +- + pub struct semid_ds { + pub sem_perm: ipc_perm, + #[cfg(target_arch = "powerpc")] +--- a/vendor/libc/src/unix/linux_like/linux/gnu/b64/aarch64/mod.rs ++++ b/vendor/libc/src/unix/linux_like/linux/gnu/b64/aarch64/mod.rs +@@ -197,12 +197,6 @@ + pub ss_size: ::size_t + } + +- pub struct ip_mreqn { +- pub imr_multiaddr: ::in_addr, +- pub imr_address: ::in_addr, +- pub imr_ifindex: ::c_int, +- } +- + pub struct seccomp_notif_sizes { + pub seccomp_notif: ::__u16, + pub seccomp_notif_resp: ::__u16, +--- a/vendor/libc/src/unix/linux_like/linux/gnu/b64/powerpc64/mod.rs ++++ b/vendor/libc/src/unix/linux_like/linux/gnu/b64/powerpc64/mod.rs +@@ -191,12 +191,6 @@ + pub ss_flags: ::c_int, + pub ss_size: ::size_t + } +- +- pub struct ip_mreqn { +- pub imr_multiaddr: ::in_addr, +- pub imr_address: ::in_addr, +- pub imr_ifindex: ::c_int, +- } + } + + pub const POSIX_FADV_DONTNEED: ::c_int = 4; +--- a/vendor/libc/src/unix/linux_like/linux/gnu/b64/riscv64/mod.rs ++++ b/vendor/libc/src/unix/linux_like/linux/gnu/b64/riscv64/mod.rs +@@ -192,12 +192,6 @@ + pub l_len: ::off64_t, + pub l_pid: ::pid_t, + } +- +- pub struct ip_mreqn { +- pub imr_multiaddr: ::in_addr, +- pub imr_address: ::in_addr, +- pub imr_ifindex: ::c_int, +- } + } + + pub const POSIX_FADV_DONTNEED: ::c_int = 4; +--- a/vendor/libc/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs ++++ b/vendor/libc/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs +@@ -260,12 +260,6 @@ + __unused5: u64 + } + +- pub struct ip_mreqn { +- pub imr_multiaddr: ::in_addr, +- pub imr_address: ::in_addr, +- pub imr_ifindex: ::c_int, +- } +- + pub struct seccomp_notif_sizes { + pub seccomp_notif: ::__u16, + pub seccomp_notif_resp: ::__u16, +--- a/vendor/libc/src/unix/linux_like/linux/musl/mod.rs ++++ b/vendor/libc/src/unix/linux_like/linux/musl/mod.rs +@@ -218,12 +218,6 @@ + pub rt_irtt: ::c_ushort, + } + +- pub struct ip_mreqn { +- pub imr_multiaddr: ::in_addr, +- pub imr_address: ::in_addr, +- pub imr_ifindex: ::c_int, +- } +- + pub struct __exit_status { + pub e_termination: ::c_short, + pub e_exit: ::c_short, +--- a/vendor/libc/src/unix/linux_like/mod.rs ++++ b/vendor/libc/src/unix/linux_like/mod.rs +@@ -25,6 +25,12 @@ + pub imr_interface: in_addr, + } + ++ pub struct ip_mreqn { ++ pub imr_multiaddr: in_addr, ++ pub imr_address: in_addr, ++ pub imr_ifindex: ::c_int, ++ } ++ + pub struct ip_mreq_source { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, diff -Nru cargo-0.54.0/debian/patches/series cargo-0.58.0/debian/patches/series --- cargo-0.54.0/debian/patches/series 2021-10-28 19:58:51.000000000 +0000 +++ cargo-0.58.0/debian/patches/series 2022-01-24 22:18:20.000000000 +0000 @@ -1,8 +1,5 @@ 2002_disable-net-tests.patch -2003_disable_close_output.patch -skip-filters_target-i386.patch -skip-filter_platform-non-amd64.patch -0001-Update-tar-dependency-to-0.4.34.patch -disable-lto-test_profiele.patch +2111-curl-no-rebuild.patch 2112-handle-4-siphasher-algorithms.patch -disable-lto-doctest.patch +filetime-pr-75.patch +libc-pr-2642.patch diff -Nru cargo-0.54.0/debian/patches/skip-filter_platform-non-amd64.patch cargo-0.58.0/debian/patches/skip-filter_platform-non-amd64.patch --- cargo-0.54.0/debian/patches/skip-filter_platform-non-amd64.patch 2021-10-28 19:57:51.000000000 +0000 +++ cargo-0.58.0/debian/patches/skip-filter_platform-non-amd64.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -https://github.com/rust-lang/cargo/issues/9238 ---- a/tests/testsuite/metadata.rs -+++ b/tests/testsuite/metadata.rs -@@ -2047,6 +2047,7 @@ - } - - #[cargo_test] -+#[cfg(target_arch = "x86_64")] - fn filter_platform() { - // Testing the --filter-platform flag. - Package::new("normal-dep", "0.0.1").publish(); diff -Nru cargo-0.54.0/debian/patches/skip-filters_target-i386.patch cargo-0.58.0/debian/patches/skip-filters_target-i386.patch --- cargo-0.54.0/debian/patches/skip-filters_target-i386.patch 2021-10-28 19:57:51.000000000 +0000 +++ cargo-0.58.0/debian/patches/skip-filters_target-i386.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ ---- a/tests/testsuite/tree.rs -+++ b/tests/testsuite/tree.rs -@@ -355,6 +355,7 @@ - } - - #[cargo_test] -+#[cfg(not(target_arch = "x86"))] - fn filters_target() { - // --target flag - if cross_compile::disabled() { diff -Nru cargo-0.54.0/debian/README.source cargo-0.58.0/debian/README.source --- cargo-0.54.0/debian/README.source 2021-10-28 19:57:51.000000000 +0000 +++ cargo-0.58.0/debian/README.source 2021-12-20 10:27:19.000000000 +0000 @@ -4,14 +4,20 @@ 0. Update debcargo-conf.git so that cargo's dependencies are up-to-date. This means less stuff will have to be patched (in debian/debcargo-conf.patch) in the next step. This might take a while, ask other people for help if needed. -1. Run d/make_orig_multi.sh . +1. Empty d/make_orig_multi-pre-vendor.sh, then run d/make_orig_multi.sh . + + If cargo-vendor tries to use too-new crates that debcargo-conf doesn't have + patches for yet, downgrade them by tweaking d/make_orig_multi-pre-vendor.sh + + e.g. cargo update -p tempfile --precise 3.1.0 2. Verify the -vendor component tarball to make sure it looks good. If not, edit d/make_orig_multi.sh and the surrounding files (such as patches and exclude files) and repeat the above until it looks good. 3. $ git fetch upstream You might have to first run: $ git remote add upstream https://github.com/rust-lang/cargo -4. $ gbp import-orig ../cargo_.orig.tar.gz +4. $ git checkout debian/experimental + $ gbp import-orig ../cargo_.orig.tar.gz If you get errors, check the extra default flags in d/gbp.conf 5. Check that no old versions remain in vendor/. If there are, then your git repo was messed up when you ran (4). Rewind the debian/sid, upstream, and @@ -22,35 +28,17 @@ General info ============ -Current packaging of cargo is sub-optimal due to the fact that -both the language (Rust) and its package manager (Cargo) -are involved into self-dependency loops to bootstrap. - -Moreover, the current approach to modules and registry by cargo is -biased towards a developer-friendly always-online use. - -This package currently resort to several workarounds to build cargo: - 1. we use a custom script (debian/bootstrap.py) to build a local - stage0, instead of downloading/embedding a snapshotted binary. - 2. we embed all dependencies crates, because cargo needs external - modules (which need cargo themself to build). - 4. we generate a .cargo/config at build-time, to override paths and - registry. - 5. we create a temporary git repository at build-time for the - registry, as this is needed by cargo. +Cargo depends on a few hundred other crates (which themselves need cargo to +build). To avoid an insane bootstrapping loop, this package therefore embeds +all dependency crates. This is made convenient by the "vendor" subcommand. + +(The alternative method, that expresses the true upstream dependencies more +faithfully, can be found in the "rust-cargo" crate, which is packaged just like +any other Debian Rust package. That is used as a library by the Debian packages +of various Rust ecosystem tools that build on top of cargo, such as our very +own debcargo. By contrast, this package is used as the actual executable +package manager, with a smaller bootstrapping requirement.) As such, the original source is composed by two tarballs: * cargo source - * dependencies crates (under vendor/), stripped of unused embedded - C libraries - -Uploading Package -================= - -Please use dgit push-source command to upload new version of the package to -archive. Command by itself creates a source only upload uploads the package to -ftpmaster and creates version history on dgit. - - dgit push-source --gbp - - -- Vasudev Kamath , Sat, 9 Jun 2018 14:41:17 +0530 + * dependencies crates (under vendor/), stripped of unused embedded C libraries diff -Nru cargo-0.54.0/debian/rules cargo-0.58.0/debian/rules --- cargo-0.54.0/debian/rules 2021-10-28 19:57:51.000000000 +0000 +++ cargo-0.58.0/debian/rules 2021-12-20 10:27:19.000000000 +0000 @@ -12,13 +12,15 @@ export CARGO_HOME = $(CURDIR)/debian/cargo_home export DEB_CARGO_CRATE=cargo_$(DEB_VERSION_UPSTREAM) -export RUSTFLAGS += --remap-path-prefix=$(CURDIR)=/usr/src/cargo-$(DEB_VERSION_UPSTREAM) +RUSTFLAGS := --remap-path-prefix=$(CURDIR)=/usr/src/cargo-$(DEB_VERSION_UPSTREAM) # https://github.com/rust-lang/rust/issues/52108 ifneq (,$(filter $(DEB_HOST_ARCH), mips64el)) RUSTFLAGS += -Ctarget-feature=+xgot endif +export RUSTFLAGS + # don't shrink, this can take ages # see https://github.com/rust-lang/cargo/issues/6490 for details export PROPTEST_MAX_SHRINK_ITERS = 0 diff -Nru cargo-0.54.0/debian/scripts/debian-cargo-vendor cargo-0.58.0/debian/scripts/debian-cargo-vendor --- cargo-0.54.0/debian/scripts/debian-cargo-vendor 2021-10-28 19:57:51.000000000 +0000 +++ cargo-0.58.0/debian/scripts/debian-cargo-vendor 2021-12-20 10:27:19.000000000 +0000 @@ -40,6 +40,9 @@ } rm -rf vendor/ +if [ -e "$CARGO_PRE_VENDOR" ]; then + "$CARGO_PRE_VENDOR" +fi cargo vendor --verbose vendor/ mkdir -p .cargo cat >.cargo/config < packages-before cp Cargo.lock Cargo.lock.orig @@ -75,6 +77,8 @@ if [ ! -d debian/patches ]; then cp -a -n "../../debcargo-conf/src/$debname/debian/patches" debian/ fi + # first unapply any patches applied in the previous iteration + QUILT_PATCHES=debian/patches quilt pop -af QUILT_PATCHES=debian/patches quilt push -a case $? in 0|2) true;; @@ -104,6 +108,7 @@ bash || true echo >&2 "$0: trying patches again..." done +rm -rf vendor/*/.pc find vendor/*/debian/patches -name '*~' -delete || true cargo update cargo lock list > packages-after @@ -111,13 +116,7 @@ # remove excluded files ( cd vendor - for i in *; do - case $i in - libgit2-sys) - continue - ;; - esac - ( +for i in *; do ( debname=$(crate_to_debcargo_conf "$i") shopt -s globstar # needed for double-glob to work in excludes cd $i diff -Nru cargo-0.54.0/debian/source/lintian-overrides cargo-0.58.0/debian/source/lintian-overrides --- cargo-0.54.0/debian/source/lintian-overrides 2021-10-28 19:57:51.000000000 +0000 +++ cargo-0.58.0/debian/source/lintian-overrides 2021-12-20 10:27:19.000000000 +0000 @@ -1,2 +1,6 @@ # debian policy bug #649530 -cargo source: missing-license-paragraph-in-dep5-copyright mpl-2.0+ (paragraph at line *) +cargo source: mismatched-override missing-license-paragraph-in-dep5-copyright mpl-2.0+ (*) +cargo source: missing-license-paragraph-in-dep5-copyright debian/copyright mpl-2.0+ (*) + +# lintian is superfluous +cargo source: superfluous-file-pattern debian/copyright * (*) diff -Nru cargo-0.54.0/debian/vendor-tarball-unsuspicious.txt cargo-0.58.0/debian/vendor-tarball-unsuspicious.txt --- cargo-0.54.0/debian/vendor-tarball-unsuspicious.txt 2021-10-28 19:57:51.000000000 +0000 +++ cargo-0.58.0/debian/vendor-tarball-unsuspicious.txt 2021-12-20 10:27:19.000000000 +0000 @@ -17,14 +17,21 @@ flate2/tests/ idna/tests/punycode_tests.json idna/tests/IdnaTest.txt +idna/tests/IdnaTestV2.txt im-rc/proptest-regressions/ +itertools/examples/iris.data openssl/test/ +memchr/src/tests/x86_64-soft_float.json miniz_oxide/tests/test_data/* regex/src/testdata/basic.dat regex/tests/ +regex-automata/data/fowler-tests/* +regex-automata/data/tests/fowler/* schannel/test/* toml/tests/ url/tests/*.json +vcpkg/test-data/*/installed/vcpkg/updates/* +vte/tests/demo.vte # ideally should be autogenerated, but too difficult today bstr/src/unicode/fsm/*.dfa @@ -39,9 +46,19 @@ rustc-demangle/src/legacy.rs rustc-demangle/src/lib.rs termion/logo.svg +tinyvec/LICENSE-MIT.md +unicode-normalization/src/stream_safe.rs +vcpkg/notes.md walkdir/compare/nftw.c winapi/src/lib.rs # other misc OK, manually audited: backtrace-sys/src/android-api.c vte/foos/large_vim_scroll.recording + +memchr/scripts/make-byte-frequency-table +idna/src/make_uts46_mapping_table.py +walkdir/compare/walk.py +strsim/dev +unicode-normalization/scripts/unicode.py +unicode-width/scripts/unicode.py diff -Nru cargo-0.54.0/.github/dependabot.yml cargo-0.58.0/.github/dependabot.yml --- cargo-0.54.0/.github/dependabot.yml 1970-01-01 00:00:00.000000000 +0000 +++ cargo-0.58.0/.github/dependabot.yml 2021-10-21 14:30:11.000000000 +0000 @@ -0,0 +1,15 @@ +version: 2 +updates: +- package-ecosystem: cargo + directory: "/" + schedule: + interval: daily + open-pull-requests-limit: 10 + reviewers: + - alexcrichton + assignees: + - alexcrichton + ignore: + - dependency-name: proptest + versions: + - ">= 0.9.a, < 0.10" diff -Nru cargo-0.54.0/.github/ISSUE_TEMPLATE/bug_report.md cargo-0.58.0/.github/ISSUE_TEMPLATE/bug_report.md --- cargo-0.54.0/.github/ISSUE_TEMPLATE/bug_report.md 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/.github/ISSUE_TEMPLATE/bug_report.md 2021-10-21 14:30:11.000000000 +0000 @@ -22,7 +22,7 @@ **Notes** -Output of `cargo version`: +Output of `cargo version --verbose`: diff -Nru cargo-0.54.0/.github/workflows/contrib.yml cargo-0.58.0/.github/workflows/contrib.yml --- cargo-0.54.0/.github/workflows/contrib.yml 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/.github/workflows/contrib.yml 2021-10-21 14:30:11.000000000 +0000 @@ -14,7 +14,7 @@ - name: Install mdbook run: | mkdir mdbook - curl -Lf https://github.com/rust-lang/mdBook/releases/download/v0.4.5/mdbook-v0.4.5-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook + curl -Lf https://github.com/rust-lang/mdBook/releases/download/v0.4.9/mdbook-v0.4.9-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook echo `pwd`/mdbook >> $GITHUB_PATH - name: Deploy docs run: | diff -Nru cargo-0.54.0/.github/workflows/main.yml cargo-0.58.0/.github/workflows/main.yml --- cargo-0.54.0/.github/workflows/main.yml 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/.github/workflows/main.yml 2021-10-21 14:30:11.000000000 +0000 @@ -54,6 +54,10 @@ 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 @@ -75,6 +79,8 @@ if: matrix.os == 'macos-latest' - run: cargo build --manifest-path crates/credential/cargo-credential-wincred/Cargo.toml if: matrix.os == 'windows-latest' + - name: Fetch smoke test + run: ci/fetch-smoke-test.sh resolver: runs-on: ubuntu-latest diff -Nru cargo-0.54.0/src/bin/cargo/cli.rs cargo-0.58.0/src/bin/cargo/cli.rs --- cargo-0.54.0/src/bin/cargo/cli.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/bin/cargo/cli.rs 2021-10-21 14:30:11.000000000 +0000 @@ -1,12 +1,26 @@ +use anyhow::anyhow; use cargo::core::{features, CliUnstable}; use cargo::{self, drop_print, drop_println, CliResult, Config}; use clap::{AppSettings, Arg, ArgMatches}; +use itertools::Itertools; +use std::collections::HashMap; +use std::fmt::Write; use super::commands; use super::list_commands; use crate::command_prelude::*; use cargo::core::features::HIDDEN; +lazy_static::lazy_static! { + // Maps from commonly known external commands (not builtin to cargo) to their + // description, for the help page. Reserved for external subcommands that are + // core within the rust ecosystem (esp ones that might become internal in the future). + static ref KNOWN_EXTERNAL_COMMAND_DESCRIPTIONS: HashMap<&'static str, &'static str> = vec![ + ("clippy", "Checks a package to catch common mistakes and improve your Rust code."), + ("fmt", "Formats all bin and lib files of the current crate using rustfmt."), + ].into_iter().collect(); +} + pub fn main(config: &mut Config) -> CliResult { // CAUTION: Be careful with using `config` until it is configured below. // In general, try to avoid loading config values unless necessary (like @@ -30,7 +44,12 @@ } }; - if args.value_of("unstable-features") == Some("help") { + // Global args need to be extracted before expanding aliases because the + // clap code for extracting a subcommand discards global options + // (appearing before the subcommand). + let (expanded_args, global_args) = expand_aliases(config, args, vec![])?; + + if expanded_args.value_of("unstable-features") == Some("help") { let options = CliUnstable::help(); let non_hidden_options: Vec<(String, String)> = options .iter() @@ -82,44 +101,51 @@ return Ok(()); } - let is_verbose = args.occurrences_of("verbose") > 0; - if args.is_present("version") { + let is_verbose = expanded_args.occurrences_of("verbose") > 0; + if expanded_args.is_present("version") { let version = get_version_string(is_verbose); drop_print!(config, "{}", version); return Ok(()); } - if let Some(code) = args.value_of("explain") { + if let Some(code) = expanded_args.value_of("explain") { let mut procss = config.load_global_rustc(None)?.process(); procss.arg("--explain").arg(code).exec()?; return Ok(()); } - if args.is_present("list") { + if expanded_args.is_present("list") { drop_println!(config, "Installed Commands:"); - for command in list_commands(config) { + for (name, command) in list_commands(config) { + let known_external_desc = KNOWN_EXTERNAL_COMMAND_DESCRIPTIONS.get(name.as_str()); match command { - CommandInfo::BuiltIn { name, about } => { + CommandInfo::BuiltIn { about } => { + assert!( + known_external_desc.is_none(), + "KNOWN_EXTERNAL_COMMANDS shouldn't contain builtin \"{}\"", + name + ); let summary = about.unwrap_or_default(); let summary = summary.lines().next().unwrap_or(&summary); // display only the first line drop_println!(config, " {:<20} {}", name, summary); } - CommandInfo::External { name, path } => { - if is_verbose { + CommandInfo::External { path } => { + if let Some(desc) = known_external_desc { + drop_println!(config, " {:<20} {}", name, desc); + } else if is_verbose { drop_println!(config, " {:<20} {}", name, path.display()); } else { drop_println!(config, " {}", name); } } + CommandInfo::Alias { target } => { + drop_println!(config, " {:<20} {}", name, target.iter().join(" ")); + } } } return Ok(()); } - // Global args need to be extracted before expanding aliases because the - // clap code for extracting a subcommand discards global options - // (appearing before the subcommand). - let (expanded_args, global_args) = expand_aliases(config, args)?; let (cmd, subcommand_args) = match expanded_args.subcommand() { (cmd, Some(args)) => (cmd, args), _ => { @@ -136,8 +162,7 @@ pub fn get_version_string(is_verbose: bool) -> String { let version = cargo::version(); - let mut version_string = version.to_string(); - version_string.push('\n'); + let mut version_string = format!("cargo {}\n", version); if is_verbose { version_string.push_str(&format!( "release: {}.{}.{}\n", @@ -149,13 +174,68 @@ version_string.push_str(&format!("commit-date: {}\n", ci.commit_date)); } } + writeln!(version_string, "host: {}", env!("RUST_HOST_TARGET")).unwrap(); + add_libgit2(&mut version_string); + add_curl(&mut version_string); + add_ssl(&mut version_string); + writeln!(version_string, "os: {}", os_info::get()).unwrap(); } version_string } +fn add_libgit2(version_string: &mut String) { + let git2_v = git2::Version::get(); + let lib_v = git2_v.libgit2_version(); + let vendored = if git2_v.vendored() { + format!("vendored") + } else { + format!("system") + }; + writeln!( + version_string, + "libgit2: {}.{}.{} (sys:{} {})", + lib_v.0, + lib_v.1, + lib_v.2, + git2_v.crate_version(), + vendored + ) + .unwrap(); +} + +fn add_curl(version_string: &mut String) { + let curl_v = curl::Version::get(); + let vendored = if curl_v.vendored() { + format!("vendored") + } else { + format!("system") + }; + writeln!( + version_string, + "libcurl: {} (sys:{} {} ssl:{})", + curl_v.version(), + curl_sys::rust_crate_version(), + vendored, + curl_v.ssl_version().unwrap_or("none") + ) + .unwrap(); +} + +fn add_ssl(version_string: &mut String) { + #[cfg(feature = "openssl")] + { + writeln!(version_string, "ssl: {}", openssl::version::version()).unwrap(); + } + #[cfg(not(feature = "openssl"))] + { + let _ = version_string; // Silence unused warning. + } +} + fn expand_aliases( config: &mut Config, args: ArgMatches<'static>, + mut already_expanded: Vec, ) -> Result<(ArgMatches<'static>, GlobalArgs), CliError> { if let (cmd, Some(args)) = args.subcommand() { match ( @@ -169,6 +249,17 @@ cmd, ))?; } + (Some(_), None) => { + // Command is built-in and is not conflicting with alias, but contains ignored values. + if let Some(mut values) = args.values_of("") { + config.shell().warn(format!( + "trailing arguments after built-in command `{}` are ignored: `{}`", + cmd, + values.join(" "), + ))?; + } + } + (None, None) => {} (_, Some(mut alias)) => { alias.extend( args.values_of("") @@ -183,10 +274,23 @@ let new_args = cli() .setting(AppSettings::NoBinaryName) .get_matches_from_safe(alias)?; - let (expanded_args, _) = expand_aliases(config, new_args)?; + + let (new_cmd, _) = new_args.subcommand(); + already_expanded.push(cmd.to_string()); + if already_expanded.contains(&new_cmd.to_string()) { + // Crash if the aliases are corecursive / unresolvable + return Err(anyhow!( + "alias {} has unresolvable recursive definition: {} -> {}", + already_expanded[0], + already_expanded.join(" -> "), + new_cmd, + ) + .into()); + } + + let (expanded_args, _) = expand_aliases(config, new_args, already_expanded)?; return Ok((expanded_args, global_args)); } - (_, None) => {} } }; @@ -308,7 +412,7 @@ build, b Compile the current package check, c Analyze the current package and report errors, but don't build object files clean Remove the target directory - doc Build this package's and its dependencies' documentation + doc, d Build this package's and its dependencies' documentation new Create a new cargo package init Create a new cargo package in an existing directory run, r Run a binary or example of the local package diff -Nru cargo-0.54.0/src/bin/cargo/commands/bench.rs cargo-0.58.0/src/bin/cargo/commands/bench.rs --- cargo-0.54.0/src/bin/cargo/commands/bench.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/bin/cargo/commands/bench.rs 2021-10-21 14:30:11.000000000 +0000 @@ -35,6 +35,7 @@ "Exclude packages from the benchmark", ) .arg_jobs() + .arg_profile("Build artifacts with the specified profile") .arg_features() .arg_target_triple("Build for the target triple") .arg_target_dir() @@ -55,11 +56,11 @@ config, CompileMode::Bench, Some(&ws), - ProfileChecking::Checked, + ProfileChecking::Custom, )?; compile_opts.build_config.requested_profile = - args.get_profile_name(config, "bench", ProfileChecking::Checked)?; + args.get_profile_name(config, "bench", ProfileChecking::Custom)?; let ops = TestOptions { no_run: args.is_present("no-run"), diff -Nru cargo-0.54.0/src/bin/cargo/commands/build.rs cargo-0.58.0/src/bin/cargo/commands/build.rs --- cargo-0.54.0/src/bin/cargo/commands/build.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/bin/cargo/commands/build.rs 2021-10-21 14:30:11.000000000 +0000 @@ -53,7 +53,7 @@ config, CompileMode::Build, Some(&ws), - ProfileChecking::Checked, + ProfileChecking::Custom, )?; if let Some(out_dir) = args.value_of_path("out-dir", config) { diff -Nru cargo-0.54.0/src/bin/cargo/commands/check.rs cargo-0.58.0/src/bin/cargo/commands/check.rs --- cargo-0.54.0/src/bin/cargo/commands/check.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/bin/cargo/commands/check.rs 2021-10-21 14:30:11.000000000 +0000 @@ -41,20 +41,11 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { let ws = args.workspace(config)?; - let test = match args.value_of("profile") { - Some("test") => true, - None => false, - Some(profile) => { - let err = anyhow::format_err!( - "unknown profile: `{}`, only `test` is \ - currently supported", - profile - ); - return Err(CliError::new(err, 101)); - } - }; + // This is a legacy behavior that causes `cargo check` to pass `--test`. + let test = matches!(args.value_of("profile"), Some("test")); let mode = CompileMode::Check { test }; - let compile_opts = args.compile_options(config, mode, Some(&ws), ProfileChecking::Unchecked)?; + let compile_opts = + args.compile_options(config, mode, Some(&ws), ProfileChecking::LegacyTestOnly)?; ops::compile(&ws, &compile_opts)?; Ok(()) diff -Nru cargo-0.54.0/src/bin/cargo/commands/clean.rs cargo-0.58.0/src/bin/cargo/commands/clean.rs --- cargo-0.54.0/src/bin/cargo/commands/clean.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/bin/cargo/commands/clean.rs 2021-10-21 14:30:11.000000000 +0000 @@ -28,7 +28,7 @@ config, spec: values(args, "package"), targets: args.targets(), - requested_profile: args.get_profile_name(config, "dev", ProfileChecking::Checked)?, + requested_profile: args.get_profile_name(config, "dev", ProfileChecking::Custom)?, profile_specified: args.is_present("profile") || args.is_present("release"), doc: args.is_present("doc"), }; diff -Nru cargo-0.54.0/src/bin/cargo/commands/describe_future_incompatibilities.rs cargo-0.58.0/src/bin/cargo/commands/describe_future_incompatibilities.rs --- cargo-0.54.0/src/bin/cargo/commands/describe_future_incompatibilities.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/bin/cargo/commands/describe_future_incompatibilities.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -use crate::command_prelude::*; -use anyhow::{anyhow, Context as _}; -use cargo::core::compiler::future_incompat::{OnDiskReport, FUTURE_INCOMPAT_FILE}; -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), - ) - .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()); - } - - let ws = args.workspace(config)?; - let report_file = ws.target_dir().open_ro( - FUTURE_INCOMPAT_FILE, - ws.config(), - "Future incompatible report", - )?; - - let mut file_contents = String::new(); - report_file - .file() - .read_to_string(&mut file_contents) - .with_context(|| "failed to read report")?; - let on_disk_report: OnDiskReport = - serde_json::from_str(&file_contents).with_context(|| "failed to load report")?; - - let id = args.value_of("id").unwrap(); - if id != on_disk_report.id { - return Err(anyhow!( - "Expected an id of `{}`, but `{}` was provided on the command line. \ - Your report may have been overwritten by a different one.", - on_disk_report.id, - id - ) - .into()); - } - - drop_eprint!(config, "{}", on_disk_report.report); - Ok(()) -} diff -Nru cargo-0.54.0/src/bin/cargo/commands/doc.rs cargo-0.58.0/src/bin/cargo/commands/doc.rs --- cargo-0.54.0/src/bin/cargo/commands/doc.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/bin/cargo/commands/doc.rs 2021-10-21 14:30:11.000000000 +0000 @@ -4,6 +4,8 @@ pub fn cli() -> App { subcommand("doc") + // subcommand aliases are handled in aliased_command() + // .alias("d") .about("Build a package's documentation") .arg(opt("quiet", "No output printed to stdout").short("q")) .arg(opt( @@ -18,10 +20,12 @@ .arg(opt("no-deps", "Don't build documentation for dependencies")) .arg(opt("document-private-items", "Document private items")) .arg_jobs() - .arg_targets_lib_bin( + .arg_targets_lib_bin_example( "Document only this package's library", "Document only the specified binary", "Document all binaries", + "Document only the specified example", + "Document all examples", ) .arg_release("Build artifacts in release mode, with optimizations") .arg_profile("Build artifacts with the specified profile") @@ -41,7 +45,7 @@ deps: !args.is_present("no-deps"), }; let mut compile_opts = - args.compile_options(config, mode, Some(&ws), ProfileChecking::Checked)?; + args.compile_options(config, mode, Some(&ws), ProfileChecking::Custom)?; compile_opts.rustdoc_document_private_items = args.is_present("document-private-items"); let doc_opts = DocOptions { diff -Nru cargo-0.54.0/src/bin/cargo/commands/fix.rs cargo-0.58.0/src/bin/cargo/commands/fix.rs --- cargo-0.54.0/src/bin/cargo/commands/fix.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/bin/cargo/commands/fix.rs 2021-10-21 14:30:11.000000000 +0000 @@ -67,23 +67,14 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { let ws = args.workspace(config)?; - let test = match args.value_of("profile") { - Some("test") => true, - None => false, - Some(profile) => { - let err = anyhow::format_err!( - "unknown profile: `{}`, only `test` is \ - currently supported", - profile - ); - return Err(CliError::new(err, 101)); - } - }; + // This is a legacy behavior that causes `cargo fix` to pass `--test`. + let test = matches!(args.value_of("profile"), Some("test")); let mode = CompileMode::Check { test }; // Unlike other commands default `cargo fix` to all targets to fix as much // code as we can. - let mut opts = args.compile_options(config, mode, Some(&ws), ProfileChecking::Unchecked)?; + let mut opts = + args.compile_options(config, mode, Some(&ws), ProfileChecking::LegacyTestOnly)?; if let CompileFilter::Default { .. } = opts.filter { opts.filter = CompileFilter::Only { diff -Nru cargo-0.54.0/src/bin/cargo/commands/init.rs cargo-0.58.0/src/bin/cargo/commands/init.rs --- cargo-0.54.0/src/bin/cargo/commands/init.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/bin/cargo/commands/init.rs 2021-10-21 14:30:11.000000000 +0000 @@ -14,9 +14,9 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { let opts = args.new_options(config)?; - ops::init(&opts, config)?; + let project_kind = ops::init(&opts, config)?; config .shell() - .status("Created", format!("{} package", opts.kind))?; + .status("Created", format!("{} package", project_kind))?; Ok(()) } diff -Nru cargo-0.54.0/src/bin/cargo/commands/install.rs cargo-0.58.0/src/bin/cargo/commands/install.rs --- cargo-0.54.0/src/bin/cargo/commands/install.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/bin/cargo/commands/install.rs 2021-10-21 14:30:11.000000000 +0000 @@ -131,11 +131,11 @@ config, CompileMode::Build, workspace.as_ref(), - ProfileChecking::Checked, + ProfileChecking::Custom, )?; compile_opts.build_config.requested_profile = - args.get_profile_name(config, "release", ProfileChecking::Checked)?; + args.get_profile_name(config, "release", ProfileChecking::Custom)?; if args.is_present("list") { ops::install_list(root, config)?; diff -Nru cargo-0.54.0/src/bin/cargo/commands/mod.rs cargo-0.58.0/src/bin/cargo/commands/mod.rs --- cargo-0.54.0/src/bin/cargo/commands/mod.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/bin/cargo/commands/mod.rs 2021-10-21 14:30:11.000000000 +0000 @@ -7,7 +7,6 @@ check::cli(), clean::cli(), config::cli(), - describe_future_incompatibilities::cli(), doc::cli(), fetch::cli(), fix::cli(), @@ -25,6 +24,7 @@ pkgid::cli(), publish::cli(), read_manifest::cli(), + report::cli(), run::cli(), rustc::cli(), rustdoc::cli(), @@ -47,7 +47,6 @@ "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 @@ "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 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 pkgid; pub mod publish; pub mod read_manifest; +pub mod report; pub mod run; pub mod rustc; pub mod rustdoc; diff -Nru cargo-0.54.0/src/bin/cargo/commands/package.rs cargo-0.58.0/src/bin/cargo/commands/package.rs --- cargo-0.54.0/src/bin/cargo/commands/package.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/bin/cargo/commands/package.rs 2021-10-21 14:30:11.000000000 +0000 @@ -28,6 +28,11 @@ .arg_target_triple("Build for the target triple") .arg_target_dir() .arg_features() + .arg_package_spec_no_all( + "Package(s) to assemble", + "Assemble all packages in the workspace", + "Don't assemble specified packages", + ) .arg_manifest_path() .arg_jobs() .after_help("Run `cargo help package` for more detailed information.\n") @@ -35,6 +40,8 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { let ws = args.workspace(config)?; + let specs = args.packages_from_flags()?; + ops::package( &ws, &PackageOpts { @@ -43,10 +50,12 @@ list: args.is_present("list"), check_metadata: !args.is_present("no-metadata"), allow_dirty: args.is_present("allow-dirty"), + to_package: specs, targets: args.targets(), jobs: args.jobs()?, cli_features: args.cli_features()?, }, )?; + Ok(()) } diff -Nru cargo-0.54.0/src/bin/cargo/commands/publish.rs cargo-0.58.0/src/bin/cargo/commands/publish.rs --- cargo-0.54.0/src/bin/cargo/commands/publish.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/bin/cargo/commands/publish.rs 2021-10-21 14:30:11.000000000 +0000 @@ -18,6 +18,7 @@ )) .arg_target_triple("Build for the target triple") .arg_target_dir() + .arg_package("Package to publish") .arg_manifest_path() .arg_features() .arg_jobs() @@ -41,6 +42,7 @@ index, verify: !args.is_present("no-verify"), allow_dirty: args.is_present("allow-dirty"), + to_publish: args.packages_from_flags()?, targets: args.targets(), jobs: args.jobs()?, dry_run: args.is_present("dry-run"), diff -Nru cargo-0.54.0/src/bin/cargo/commands/report.rs cargo-0.58.0/src/bin/cargo/commands/report.rs --- cargo-0.54.0/src/bin/cargo/commands/report.rs 1970-01-01 00:00:00.000000000 +0000 +++ cargo-0.58.0/src/bin/cargo/commands/report.rs 2021-10-21 14:30:11.000000000 +0000 @@ -0,0 +1,45 @@ +use crate::command_prelude::*; +use anyhow::anyhow; +use cargo::core::compiler::future_incompat::{OnDiskReports, REPORT_PREAMBLE}; +use cargo::drop_println; + +pub fn cli() -> App { + 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") + .alias("future-incompat") + .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"), + ), + ) +} + +pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { + if !config.nightly_features_allowed { + 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 reports = OnDiskReports::load(&ws)?; + let id = args + .value_of_u32("id")? + .unwrap_or_else(|| reports.last_id()); + let report = reports.get_report(id, config)?; + drop_println!(config, "{}", REPORT_PREAMBLE); + drop(config.shell().print_ansi_stdout(report.as_bytes())); + Ok(()) +} diff -Nru cargo-0.54.0/src/bin/cargo/commands/run.rs cargo-0.58.0/src/bin/cargo/commands/run.rs --- cargo-0.54.0/src/bin/cargo/commands/run.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/bin/cargo/commands/run.rs 2021-10-21 14:30:11.000000000 +0000 @@ -37,7 +37,7 @@ config, CompileMode::Build, Some(&ws), - ProfileChecking::Checked, + ProfileChecking::Custom, )?; // Disallow `spec` to be an glob pattern diff -Nru cargo-0.54.0/src/bin/cargo/commands/rustc.rs cargo-0.58.0/src/bin/cargo/commands/rustc.rs --- cargo-0.54.0/src/bin/cargo/commands/rustc.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/bin/cargo/commands/rustc.rs 2021-10-21 14:30:11.000000000 +0000 @@ -1,6 +1,6 @@ use crate::command_prelude::*; - use cargo::ops; +use cargo::util::interning::InternedString; const PRINT_ARG_NAME: &str = "print"; @@ -46,26 +46,24 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { let ws = args.workspace(config)?; + // This is a legacy behavior that changes the behavior based on the profile. + // If we want to support this more formally, I think adding a --mode flag + // would be warranted. let mode = match args.value_of("profile") { - Some("dev") | None => CompileMode::Build, Some("test") => CompileMode::Test, Some("bench") => CompileMode::Bench, Some("check") => CompileMode::Check { test: false }, - Some(mode) => { - let err = anyhow::format_err!( - "unknown profile: `{}`, use dev, - test, or bench", - mode - ); - return Err(CliError::new(err, 101)); - } + _ => CompileMode::Build, }; let mut compile_opts = args.compile_options_for_single_package( config, mode, Some(&ws), - ProfileChecking::Unchecked, + ProfileChecking::LegacyRustc, )?; + if compile_opts.build_config.requested_profile == "check" { + compile_opts.build_config.requested_profile = InternedString::new("dev"); + } let target_args = values(args, "args"); compile_opts.target_rustc_args = if target_args.is_empty() { None @@ -75,7 +73,7 @@ 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)?; diff -Nru cargo-0.54.0/src/bin/cargo/commands/rustdoc.rs cargo-0.58.0/src/bin/cargo/commands/rustdoc.rs --- cargo-0.54.0/src/bin/cargo/commands/rustdoc.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/bin/cargo/commands/rustdoc.rs 2021-10-21 14:30:11.000000000 +0000 @@ -44,7 +44,7 @@ config, CompileMode::Doc { deps: false }, Some(&ws), - ProfileChecking::Checked, + ProfileChecking::Custom, )?; let target_args = values(args, "args"); compile_opts.target_rustdoc_args = if target_args.is_empty() { diff -Nru cargo-0.54.0/src/bin/cargo/commands/test.rs cargo-0.58.0/src/bin/cargo/commands/test.rs --- cargo-0.54.0/src/bin/cargo/commands/test.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/bin/cargo/commands/test.rs 2021-10-21 14:30:11.000000000 +0000 @@ -66,11 +66,11 @@ config, CompileMode::Test, Some(&ws), - ProfileChecking::Checked, + ProfileChecking::Custom, )?; compile_opts.build_config.requested_profile = - args.get_profile_name(config, "test", ProfileChecking::Checked)?; + args.get_profile_name(config, "test", ProfileChecking::Custom)?; // `TESTNAME` is actually an argument of the test binary, but it's // important, so we explicitly mention it and reconfigure. diff -Nru cargo-0.54.0/src/bin/cargo/commands/tree.rs cargo-0.58.0/src/bin/cargo/commands/tree.rs --- cargo-0.54.0/src/bin/cargo/commands/tree.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/bin/cargo/commands/tree.rs 2021-10-21 14:30:11.000000000 +0000 @@ -43,7 +43,8 @@ "edges", "KINDS", "The kinds of dependencies to display \ - (features, normal, build, dev, all, no-dev, no-build, no-normal)", + (features, normal, build, dev, all, \ + no-normal, no-build, no-dev, no-proc-macro)", ) .short("e"), ) @@ -55,6 +56,12 @@ ) .short("i"), ) + .arg(multi_opt( + "prune", + "SPEC", + "Prune the given package from the display of the dependency tree", + )) + .arg(opt("depth", "Maximum display depth of the dependency tree").value_name("DEPTH")) // Deprecated, use --prefix=none instead. .arg(Arg::with_name("no-indent").long("no-indent").hidden(true)) // Deprecated, use --prefix=depth instead. @@ -147,9 +154,11 @@ }; let target = tree::Target::from_cli(targets); - let edge_kinds = parse_edge_kinds(config, args)?; + let (edge_kinds, no_proc_macro) = parse_edge_kinds(config, args)?; let graph_features = edge_kinds.contains(&EdgeKind::Feature); + let pkgs_to_prune = args._values_of("prune"); + let packages = args.packages_from_flags()?; let mut invert = args .values_of("invert") @@ -195,31 +204,59 @@ target, edge_kinds, invert, + pkgs_to_prune, prefix, no_dedupe, duplicates: args.is_present("duplicates"), charset, format: args.value_of("format").unwrap().to_string(), graph_features, + max_display_depth: args.value_of_u32("depth")?.unwrap_or(u32::MAX), + no_proc_macro, }; + if opts.graph_features && opts.duplicates { + return Err(format_err!("the `-e features` flag does not support `--duplicates`").into()); + } + tree::build_and_print(&ws, &opts)?; Ok(()) } -fn parse_edge_kinds(config: &Config, args: &ArgMatches<'_>) -> CargoResult> { - let mut kinds: Vec<&str> = args - .values_of("edges") - .map_or_else(|| Vec::new(), |es| es.flat_map(|e| e.split(',')).collect()); - if args.is_present("no-dev-dependencies") { - config - .shell() - .warn("the --no-dev-dependencies flag has changed to -e=no-dev")?; - kinds.push("no-dev"); - } - if kinds.is_empty() { - kinds.extend(&["normal", "build", "dev"]); - } +/// Parses `--edges` option. +/// +/// Returns a tuple of `EdgeKind` map and `no_proc_marco` flag. +fn parse_edge_kinds( + config: &Config, + args: &ArgMatches<'_>, +) -> CargoResult<(HashSet, bool)> { + let (kinds, no_proc_macro) = { + let mut no_proc_macro = false; + let mut kinds = args.values_of("edges").map_or_else( + || Vec::new(), + |es| { + es.flat_map(|e| e.split(',')) + .filter(|e| { + no_proc_macro = *e == "no-proc-macro"; + !no_proc_macro + }) + .collect() + }, + ); + + if args.is_present("no-dev-dependencies") { + config + .shell() + .warn("the --no-dev-dependencies flag has changed to -e=no-dev")?; + kinds.push("no-dev"); + } + + if kinds.is_empty() { + kinds.extend(&["normal", "build", "dev"]); + } + + (kinds, no_proc_macro) + }; let mut result = HashSet::new(); let insert_defaults = |result: &mut HashSet| { @@ -231,7 +268,7 @@ bail!( "unknown edge kind `{}`, valid values are \ \"normal\", \"build\", \"dev\", \ - \"no-normal\", \"no-build\", \"no-dev\", \ + \"no-normal\", \"no-build\", \"no-dev\", \"no-proc-macro\", \ \"features\", or \"all\"", k ) @@ -245,12 +282,17 @@ "no-dev" => result.remove(&EdgeKind::Dep(DepKind::Development)), "features" => result.insert(EdgeKind::Feature), "normal" | "build" | "dev" | "all" => { - bail!("`no-` dependency kinds cannot be mixed with other dependency kinds") + bail!( + "`{}` dependency kind cannot be mixed with \ + \"no-normal\", \"no-build\", or \"no-dev\" \ + dependency kinds", + kind + ) } k => return unknown(k), }; } - return Ok(result); + return Ok((result, no_proc_macro)); } for kind in &kinds { match *kind { @@ -276,5 +318,5 @@ if kinds.len() == 1 && kinds[0] == "features" { insert_defaults(&mut result); } - Ok(result) + Ok((result, no_proc_macro)) } diff -Nru cargo-0.54.0/src/bin/cargo/main.rs cargo-0.58.0/src/bin/cargo/main.rs --- cargo-0.54.0/src/bin/cargo/main.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/bin/cargo/main.rs 2021-10-21 14:30:11.000000000 +0000 @@ -4,10 +4,11 @@ #![warn(clippy::redundant_clone)] use cargo::core::shell::Shell; +use cargo::util::toml::StringOrVec; use cargo::util::CliError; use cargo::util::{self, closest_msg, command_prelude, CargoResult, CliResult, Config}; use cargo_util::{ProcessBuilder, ProcessError}; -use std::collections::{BTreeMap, BTreeSet}; +use std::collections::BTreeMap; use std::env; use std::fs; use std::path::{Path, PathBuf}; @@ -48,9 +49,10 @@ /// Table for defining the aliases which come builtin in `Cargo`. /// The contents are structured as: `(alias, aliased_command, description)`. -const BUILTIN_ALIASES: [(&str, &str, &str); 4] = [ +const BUILTIN_ALIASES: [(&str, &str, &str); 5] = [ ("b", "build", "alias: build"), ("c", "check", "alias: check"), + ("d", "doc", "alias: doc"), ("r", "run", "alias: run"), ("t", "test", "alias: test"), ]; @@ -82,10 +84,10 @@ } /// List all runnable commands -fn list_commands(config: &Config) -> BTreeSet { +fn list_commands(config: &Config) -> BTreeMap { let prefix = "cargo-"; let suffix = env::consts::EXE_SUFFIX; - let mut commands = BTreeSet::new(); + let mut commands = BTreeMap::new(); for dir in search_directories(config) { let entries = match fs::read_dir(dir) { Ok(entries) => entries, @@ -102,39 +104,47 @@ } if is_executable(entry.path()) { let end = filename.len() - suffix.len(); - commands.insert(CommandInfo::External { - name: filename[prefix.len()..end].to_string(), - path: path.clone(), - }); + commands.insert( + filename[prefix.len()..end].to_string(), + CommandInfo::External { path: path.clone() }, + ); } } } for cmd in commands::builtin() { - commands.insert(CommandInfo::BuiltIn { - name: cmd.get_name().to_string(), - about: cmd.p.meta.about.map(|s| s.to_string()), - }); + commands.insert( + cmd.get_name().to_string(), + CommandInfo::BuiltIn { + about: cmd.p.meta.about.map(|s| s.to_string()), + }, + ); } // Add the builtin_aliases and them descriptions to the - // `commands` `BTreeSet`. + // `commands` `BTreeMap`. for command in &BUILTIN_ALIASES { - commands.insert(CommandInfo::BuiltIn { - name: command.0.to_string(), - about: Some(command.2.to_string()), - }); + commands.insert( + command.0.to_string(), + CommandInfo::BuiltIn { + about: Some(command.2.to_string()), + }, + ); } - commands -} - -/// List all runnable aliases -fn list_aliases(config: &Config) -> Vec { - match config.get::>("alias") { - Ok(aliases) => aliases.keys().map(|a| a.to_string()).collect(), - Err(_) => Vec::new(), + // Add the user-defined aliases + if let Ok(aliases) = config.get::>("alias") { + for (name, target) in aliases.iter() { + commands.insert( + name.to_string(), + CommandInfo::Alias { + target: target.clone(), + }, + ); + } } + + commands } fn execute_external_subcommand(config: &Config, cmd: &str, args: &[&str]) -> CliResult { @@ -146,13 +156,8 @@ let command = match path { Some(command) => command, None => { - let commands: Vec = list_commands(config) - .iter() - .map(|c| c.name().to_string()) - .collect(); - let aliases = list_aliases(config); - let suggestions = commands.iter().chain(aliases.iter()); - let did_you_mean = closest_msg(cmd, suggestions, |c| c); + let suggestions = list_commands(config); + let did_you_mean = closest_msg(cmd, suggestions.keys(), |c| c); let err = anyhow::format_err!("no such subcommand: `{}`{}", cmd, did_you_mean); return Err(CliError::new(err, 101)); } diff -Nru cargo-0.54.0/src/cargo/core/compiler/build_config.rs cargo-0.58.0/src/cargo/core/compiler/build_config.rs --- cargo-0.54.0/src/cargo/core/compiler/build_config.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/cargo/core/compiler/build_config.rs 2021-10-21 14:30:11.000000000 +0000 @@ -69,6 +69,9 @@ )?; } let jobs = jobs.or(cfg.jobs).unwrap_or(::num_cpus::get() as u32); + if jobs == 0 { + anyhow::bail!("jobs may not be 0"); + } Ok(BuildConfig { requested_kinds, diff -Nru cargo-0.54.0/src/cargo/core/compiler/build_context/target_info.rs cargo-0.58.0/src/cargo/core/compiler/build_context/target_info.rs --- cargo-0.54.0/src/cargo/core/compiler/build_context/target_info.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/cargo/core/compiler/build_context/target_info.rs 2021-10-21 14:30:11.000000000 +0000 @@ -47,6 +47,8 @@ pub rustdocflags: Vec, /// Whether or not rustc supports the `-Csplit-debuginfo` flag. pub supports_split_debuginfo: bool, + /// Whether or not rustc supports the `--force-warn` flag. Remove after 1.56 is stable. + pub supports_force_warn: bool, } /// Kind of each file generated by a Unit, part of `FileType`. @@ -103,11 +105,18 @@ /// The filename for this FileType that Cargo should use when "uplifting" /// it to the destination directory. pub fn uplift_filename(&self, target: &Target) -> String { - let name = if self.should_replace_hyphens { - target.crate_name() - } else { - target.name().to_string() + let name = match target.binary_filename() { + Some(name) => name, + None => { + // For binary crate type, `should_replace_hyphens` will always be false. + if self.should_replace_hyphens { + target.crate_name() + } else { + target.name().to_string() + } + } }; + format!("{}{}{}", self.prefix, name, self.suffix) } @@ -171,6 +180,12 @@ extra_fingerprint, ) .is_ok(); + let supports_force_warn = rustc + .cached_output( + process.clone().arg("--force-warn=rust-2021-compatibility"), + extra_fingerprint, + ) + .is_ok(); process.arg("--print=sysroot"); process.arg("--print=cfg"); @@ -246,6 +261,7 @@ )?, cfg, supports_split_debuginfo, + supports_force_warn, }) } @@ -548,6 +564,7 @@ /// /// The locations are: /// +/// - the `CARGO_ENCODED_RUSTFLAGS` environment variable /// - the `RUSTFLAGS` environment variable /// /// then if this was not found @@ -595,7 +612,16 @@ return Ok(Vec::new()); } - // First try RUSTFLAGS from the environment + // First try CARGO_ENCODED_RUSTFLAGS from the environment. + // Prefer this over RUSTFLAGS since it's less prone to encoding errors. + if let Ok(a) = env::var(format!("CARGO_ENCODED_{}", name)) { + if a.is_empty() { + return Ok(Vec::new()); + } + return Ok(a.split('\x1f').map(str::to_string).collect()); + } + + // Then try RUSTFLAGS from the environment if let Ok(a) = env::var(name) { let args = a .split(' ') @@ -682,10 +708,15 @@ ) -> CargoResult> { let config = ws.config(); let rustc = config.load_global_rustc(Some(ws))?; - let host_config = config.target_cfg_triple(&rustc.host)?; - let host_info = TargetInfo::new(config, requested_kinds, &rustc, CompileKind::Host)?; let mut target_config = HashMap::new(); let mut target_info = HashMap::new(); + let target_applies_to_host = config.target_applies_to_host()?; + let host_info = TargetInfo::new(config, requested_kinds, &rustc, CompileKind::Host)?; + let host_config = if target_applies_to_host { + config.target_cfg_triple(&rustc.host)? + } else { + config.host_cfg_triple(&rustc.host)? + }; // This is a hack. The unit_dependency graph builder "pretends" that // `CompileKind::Host` is `CompileKind::Target(host)` if the @@ -695,8 +726,8 @@ if requested_kinds.iter().any(CompileKind::is_host) { let ct = CompileTarget::new(&rustc.host)?; target_info.insert(ct, host_info.clone()); - target_config.insert(ct, host_config.clone()); - } + target_config.insert(ct, config.target_cfg_triple(&rustc.host)?); + }; let mut res = RustcTargetData { rustc, diff -Nru cargo-0.54.0/src/cargo/core/compiler/compilation.rs cargo-0.58.0/src/cargo/core/compiler/compilation.rs --- cargo-0.54.0/src/cargo/core/compiler/compilation.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/cargo/core/compiler/compilation.rs 2021-10-21 14:30:11.000000000 +0000 @@ -5,7 +5,6 @@ use cargo_platform::CfgExpr; use cargo_util::{paths, ProcessBuilder}; -use semver::Version; use super::BuildContext; use crate::core::compiler::{CompileKind, Metadata, Unit}; @@ -52,6 +51,9 @@ /// An array of all cdylibs created. pub cdylibs: Vec, + /// The crate names of the root units specified on the command-line. + pub root_crate_names: Vec, + /// All directories for the output of native build commands. /// /// This is currently used to drive some entries which are added to the @@ -137,6 +139,7 @@ tests: Vec::new(), binaries: Vec::new(), cdylibs: Vec::new(), + root_crate_names: Vec::new(), extra_env: HashMap::new(), to_doc_test: Vec::new(), config: bcx.config, @@ -316,10 +319,7 @@ .env("CARGO_PKG_VERSION_MAJOR", &pkg.version().major.to_string()) .env("CARGO_PKG_VERSION_MINOR", &pkg.version().minor.to_string()) .env("CARGO_PKG_VERSION_PATCH", &pkg.version().patch.to_string()) - .env( - "CARGO_PKG_VERSION_PRE", - &pre_version_component(pkg.version()), - ) + .env("CARGO_PKG_VERSION_PRE", pkg.version().pre.as_str()) .env("CARGO_PKG_VERSION", &pkg.version().to_string()) .env("CARGO_PKG_NAME", &*pkg.name()) .env( @@ -345,12 +345,15 @@ .env("CARGO_PKG_AUTHORS", &pkg.authors().join(":")) .cwd(pkg.root()); - if self.config.cli_unstable().configurable_env { - // Apply any environment variables from the config - for (key, value) in self.config.env_config()?.iter() { - if value.is_force() || cmd.get_env(key).is_none() { - cmd.env(key, value.resolve(self.config)); - } + // Apply any environment variables from the config + for (key, value) in self.config.env_config()?.iter() { + // never override a value that has already been set by cargo + if cmd.get_envs().contains_key(key) { + continue; + } + + if value.is_force() || env::var_os(key).is_none() { + cmd.env(key, value.resolve(self.config)); } } @@ -362,29 +365,17 @@ /// that are only relevant in a context that has a unit fn fill_rustc_tool_env(mut cmd: ProcessBuilder, unit: &Unit) -> ProcessBuilder { if unit.target.is_bin() { - cmd.env("CARGO_BIN_NAME", unit.target.name()); + let name = unit + .target + .binary_filename() + .unwrap_or(unit.target.name().to_string()); + + cmd.env("CARGO_BIN_NAME", name); } cmd.env("CARGO_CRATE_NAME", unit.target.crate_name()); cmd } -fn pre_version_component(v: &Version) -> String { - if v.pre.is_empty() { - return String::new(); - } - - let mut ret = String::new(); - - for (i, x) in v.pre.iter().enumerate() { - if i != 0 { - ret.push('.') - }; - ret.push_str(&x.to_string()); - } - - ret -} - fn target_runner( bcx: &BuildContext<'_, '_>, kind: CompileKind, diff -Nru cargo-0.54.0/src/cargo/core/compiler/context/compilation_files.rs cargo-0.58.0/src/cargo/core/compiler/context/compilation_files.rs --- cargo-0.54.0/src/cargo/core/compiler/context/compilation_files.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/cargo/core/compiler/context/compilation_files.rs 2021-10-21 14:30:11.000000000 +0000 @@ -467,6 +467,9 @@ let meta = &self.metas[unit]; let meta_opt = meta.use_extra_filename.then(|| meta.meta_hash.to_string()); let path = out_dir.join(file_type.output_filename(&unit.target, meta_opt.as_deref())); + + // If, the `different_binary_name` feature is enabled, the name of the hardlink will + // be the name of the binary provided by the user in `Cargo.toml`. let hardlink = self.uplift_to(unit, &file_type, &path); let export_path = if unit.target.is_custom_build() { None @@ -595,7 +598,7 @@ // // This assumes that the first segment is the important bit ("nightly", // "beta", "dev", etc.). Skip other parts like the `.3` in `-beta.3`. - vers.pre[0].hash(hasher); + vers.pre.split('.').next().hash(hasher); // Keep "host" since some people switch hosts to implicitly change // targets, (like gnu vs musl or gnu vs msvc). In the future, we may want // to consider hashing `unit.kind.short_name()` instead. @@ -626,19 +629,13 @@ // No metadata in these cases: // // - dylibs: - // - macOS encodes the dylib name in the executable, so it can't be renamed. - // - TODO: Are there other good reasons? If not, maybe this should be macos specific? + // - if any dylib names are encoded in executables, so they can't be renamed. + // - TODO: Maybe use `-install-name` on macOS or `-soname` on other UNIX systems + // to specify the dylib name to be used by the linker instead of the filename. // - Windows MSVC executables: The path to the PDB is embedded in the // executable, and we don't want the PDB path to include the hash in it. - // - wasm32 executables: When using emscripten, the path to the .wasm file - // is embedded in the .js file, so we don't want the hash in there. - // TODO: Is this necessary for wasm32-unknown-unknown? - // - apple executables: The executable name is used in the dSYM directory - // (such as `target/debug/foo.dSYM/Contents/Resources/DWARF/foo-64db4e4bf99c12dd`). - // Unfortunately this causes problems with our current backtrace - // implementation which looks for a file matching the exe name exactly. - // See https://github.com/rust-lang/rust/issues/72550#issuecomment-638501691 - // for more details. + // - wasm32-unknown-emscripten executables: When using emscripten, the path to the + // .wasm file is embedded in the .js file, so we don't want the hash in there. // // This is only done for local packages, as we don't expect to export // dependencies. @@ -647,14 +644,14 @@ // force metadata in the hash. This is only used for building libstd. For // example, if libstd is placed in a common location, we don't want a file // named /usr/lib/libstd.so which could conflict with other rustc - // installs. TODO: Is this still a realistic concern? + // installs. In addition it prevents accidentally loading a libstd of a + // different compiler at runtime. // See https://github.com/rust-lang/cargo/issues/3005 let short_name = bcx.target_data.short_name(&unit.kind); if (unit.target.is_dylib() || unit.target.is_cdylib() - || (unit.target.is_executable() && short_name.starts_with("wasm32-")) - || (unit.target.is_executable() && short_name.contains("msvc")) - || (unit.target.is_executable() && short_name.contains("-apple-"))) + || (unit.target.is_executable() && short_name == "wasm32-unknown-emscripten") + || (unit.target.is_executable() && short_name.contains("msvc"))) && unit.pkg.package_id().source_id().is_path() && env::var("__CARGO_DEFAULT_LIB_METADATA").is_err() { diff -Nru cargo-0.54.0/src/cargo/core/compiler/context/mod.rs cargo-0.58.0/src/cargo/core/compiler/context/mod.rs --- cargo-0.54.0/src/cargo/core/compiler/context/mod.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/cargo/core/compiler/context/mod.rs 2021-10-21 14:30:11.000000000 +0000 @@ -2,7 +2,7 @@ use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex}; -use anyhow::Context as _; +use anyhow::{bail, Context as _}; use filetime::FileTime; use jobserver::Client; @@ -195,12 +195,12 @@ self.compilation .binaries .push(self.unit_output(unit, bindst)); - } else if unit.target.is_cdylib() { - if !self.compilation.cdylibs.iter().any(|uo| uo.unit == *unit) { - self.compilation - .cdylibs - .push(self.unit_output(unit, bindst)); - } + } else if unit.target.is_cdylib() + && !self.compilation.cdylibs.iter().any(|uo| uo.unit == *unit) + { + self.compilation + .cdylibs + .push(self.unit_output(unit, bindst)); } } @@ -309,6 +309,9 @@ } self.primary_packages .extend(self.bcx.roots.iter().map(|u| u.pkg.package_id())); + self.compilation + .root_crate_names + .extend(self.bcx.roots.iter().map(|u| u.target.crate_name())); self.record_units_requiring_metadata(); @@ -467,7 +470,7 @@ If this looks unexpected, it may be a bug in Cargo. Please file a bug report at\n\ https://github.com/rust-lang/cargo/issues/ with as much information as you\n\ can provide.\n\ - {} running on `{}` target `{}`\n\ + cargo {} running on `{}` target `{}`\n\ First unit: {:?}\n\ Second unit: {:?}", describe_collision(unit, other_unit, path), @@ -480,6 +483,22 @@ } }; + fn doc_collision_error(unit: &Unit, other_unit: &Unit) -> CargoResult<()> { + bail!( + "document output filename collision\n\ + The {} `{}` in package `{}` has the same name as the {} `{}` in package `{}`.\n\ + Only one may be documented at once since they output to the same path.\n\ + Consider documenting only one, renaming one, \ + or marking one with `doc = false` in Cargo.toml.", + unit.target.kind().description(), + unit.target.name(), + unit.pkg, + other_unit.target.kind().description(), + other_unit.target.name(), + other_unit.pkg, + ); + } + let mut keys = self .bcx .unit_graph @@ -488,7 +507,30 @@ .collect::>(); // Sort for consistent error messages. keys.sort_unstable(); + // These are kept separate to retain compatibility with older + // versions, which generated an error when there was a duplicate lib + // or bin (but the old code did not check bin<->lib collisions). To + // retain backwards compatibility, this only generates an error for + // duplicate libs or duplicate bins (but not both). Ideally this + // shouldn't be here, but since there isn't a complete workaround, + // yet, this retains the old behavior. + let mut doc_libs = HashMap::new(); + let mut doc_bins = HashMap::new(); for unit in keys { + if unit.mode.is_doc() && self.is_primary_package(unit) { + // These situations have been an error since before 1.0, so it + // is not a warning like the other situations. + if unit.target.is_lib() { + if let Some(prev) = doc_libs.insert((unit.target.crate_name(), unit.kind), unit) + { + doc_collision_error(unit, prev)?; + } + } else if let Some(prev) = + doc_bins.insert((unit.target.crate_name(), unit.kind), unit) + { + doc_collision_error(unit, prev)?; + } + } for output in self.outputs(unit)?.iter() { if let Some(other_unit) = output_collisions.insert(output.path.clone(), unit) { if unit.mode.is_doc() { diff -Nru cargo-0.54.0/src/cargo/core/compiler/custom_build.rs cargo-0.58.0/src/cargo/core/compiler/custom_build.rs --- cargo-0.54.0/src/cargo/core/compiler/custom_build.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/cargo/core/compiler/custom_build.rs 2021-10-21 14:30:11.000000000 +0000 @@ -2,11 +2,11 @@ use super::{fingerprint, Context, LinkType, Unit}; use crate::core::compiler::context::Metadata; use crate::core::compiler::job_queue::JobState; -use crate::core::{profiles::ProfileRoot, PackageId}; +use crate::core::{profiles::ProfileRoot, PackageId, Target}; use crate::util::errors::CargoResult; use crate::util::machine_message::{self, Message}; use crate::util::{internal, profile}; -use anyhow::Context as _; +use anyhow::{bail, Context as _}; use cargo_platform::Cfg; use cargo_util::paths; use std::collections::hash_map::{Entry, HashMap}; @@ -25,7 +25,7 @@ /// Names and link kinds of libraries, suitable for the `-l` flag. pub library_links: Vec, /// Linker arguments suitable to be passed to `-C link-arg=` - pub linker_args: Vec<(Option, String)>, + pub linker_args: Vec<(LinkType, String)>, /// Various `--cfg` flags to pass to the compiler. pub cfgs: Vec, /// Additional environment variables to run the compiler with. @@ -38,6 +38,9 @@ /// Environment variables which, when changed, will cause a rebuild. pub rerun_if_env_changed: Vec, /// Warnings generated by this build. + /// + /// These are only displayed if this is a "local" package, `-vv` is used, + /// or there is a build error for any target in this package. pub warnings: Vec, } @@ -126,7 +129,7 @@ } fn emit_build_output( - state: &JobState<'_>, + state: &JobState<'_, '_>, output: &BuildOutput, out_dir: &Path, package_id: PackageId, @@ -249,6 +252,24 @@ } } + // Also inform the build script of the rustc compiler context. + if let Some(wrapper) = bcx.rustc().wrapper.as_ref() { + cmd.env("RUSTC_WRAPPER", wrapper); + } else { + cmd.env_remove("RUSTC_WRAPPER"); + } + cmd.env_remove("RUSTC_WORKSPACE_WRAPPER"); + if cx.bcx.ws.is_member(&unit.pkg) { + if let Some(wrapper) = bcx.rustc().workspace_wrapper.as_ref() { + cmd.env("RUSTC_WORKSPACE_WRAPPER", wrapper); + } + } + cmd.env( + "CARGO_ENCODED_RUSTFLAGS", + bcx.rustflags_args(unit).join("\x1f"), + ); + cmd.env_remove("RUSTFLAGS"); + // Gather the set of native dependencies that this package has along with // some other variables to close over. // @@ -294,8 +315,10 @@ paths::create_dir_all(&script_dir)?; paths::create_dir_all(&script_out_dir)?; - let extra_link_arg = cx.bcx.config.cli_unstable().extra_link_arg; let nightly_features_allowed = cx.bcx.config.nightly_features_allowed; + let targets: Vec = unit.pkg.targets().to_vec(); + // Need a separate copy for the fresh closure. + let targets_fresh = targets.clone(); // Prepare the unit of "dirty work" which will actually run the custom build // command. @@ -403,8 +426,8 @@ &pkg_descr, &script_out_dir, &script_out_dir, - extra_link_arg, nightly_features_allowed, + &targets, )?; if json_messages { @@ -430,8 +453,8 @@ &pkg_descr, &prev_script_out_dir, &script_out_dir, - extra_link_arg, nightly_features_allowed, + &targets_fresh, )?, }; @@ -482,8 +505,8 @@ pkg_descr: &str, script_out_dir_when_generated: &Path, script_out_dir: &Path, - extra_link_arg: bool, nightly_features_allowed: bool, + targets: &[Target], ) -> CargoResult { let contents = paths::read_bytes(path)?; BuildOutput::parse( @@ -492,8 +515,8 @@ pkg_descr, script_out_dir_when_generated, script_out_dir, - extra_link_arg, nightly_features_allowed, + targets, ) } @@ -507,8 +530,8 @@ pkg_descr: &str, script_out_dir_when_generated: &Path, script_out_dir: &Path, - extra_link_arg: bool, nightly_features_allowed: bool, + targets: &[Target], ) -> CargoResult { let mut library_paths = Vec::new(); let mut library_links = Vec::new(); @@ -543,7 +566,11 @@ let (key, value) = match (key, value) { (Some(a), Some(b)) => (a, b.trim_end()), // Line started with `cargo:` but didn't match `key=value`. - _ => anyhow::bail!("Wrong output in {}: `{}`", whence, line), + _ => bail!("invalid output in {}: `{}`\n\ + Expected a line with `cargo:key=value` with an `=` character, \ + but none was found.\n\ + See https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script \ + for more information about build script outputs.", whence, line), }; // This will rewrite paths if the target directory has been moved. @@ -552,7 +579,7 @@ script_out_dir.to_str().unwrap(), ); - // Keep in sync with TargetConfig::new. + // Keep in sync with TargetConfig::parse_links_overrides. match key { "rustc-flags" => { let (paths, links) = BuildOutput::parse_rustc_flags(&value, &whence)?; @@ -562,21 +589,62 @@ "rustc-link-lib" => library_links.push(value.to_string()), "rustc-link-search" => library_paths.push(PathBuf::from(value)), "rustc-link-arg-cdylib" | "rustc-cdylib-link-arg" => { - linker_args.push((Some(LinkType::Cdylib), value)) + if !targets.iter().any(|target| target.is_cdylib()) { + warnings.push(format!( + "cargo:{} was specified in the build script of {}, \ + but that package does not contain a cdylib target\n\ + \n\ + Allowing this was an unintended change in the 1.50 \ + release, and may become an error in the future. \ + For more information, see \ + .", + key, pkg_descr + )); + } + linker_args.push((LinkType::Cdylib, value)) } "rustc-link-arg-bins" => { - if extra_link_arg { - linker_args.push((Some(LinkType::Bin), value)); - } else { - warnings.push(format!("cargo:{} requires -Zextra-link-arg flag", key)); + if !targets.iter().any(|target| target.is_bin()) { + bail!( + "invalid instruction `cargo:{}` from {}\n\ + The package {} does not have a bin target.", + key, + whence, + pkg_descr + ); } + linker_args.push((LinkType::Bin, value)); } - "rustc-link-arg" => { - if extra_link_arg { - linker_args.push((None, value)); - } else { - warnings.push(format!("cargo:{} requires -Zextra-link-arg flag", key)); + "rustc-link-arg-bin" => { + let mut parts = value.splitn(2, '='); + let bin_name = parts.next().unwrap().to_string(); + let arg = parts.next().ok_or_else(|| { + anyhow::format_err!( + "invalid instruction `cargo:{}={}` from {}\n\ + The instruction should have the form cargo:{}=BIN=ARG", + key, + value, + whence, + key + ) + })?; + if !targets + .iter() + .any(|target| target.is_bin() && target.name() == bin_name) + { + bail!( + "invalid instruction `cargo:{}` from {}\n\ + The package {} does not have a bin target with the name `{}`.", + key, + whence, + pkg_descr, + bin_name + ); } + linker_args.push((LinkType::SingleBin(bin_name), arg.to_string())); + } + "rustc-link-arg" => { + linker_args.push((LinkType::All, value)); } "rustc-cfg" => cfgs.push(value.to_string()), "rustc-env" => { @@ -614,7 +682,7 @@ } else { // Setting RUSTC_BOOTSTRAP would change the behavior of the crate. // Abort with an error. - anyhow::bail!("Cannot set `RUSTC_BOOTSTRAP={}` from {}.\n\ + bail!("Cannot set `RUSTC_BOOTSTRAP={}` from {}.\n\ note: Crates cannot set `RUSTC_BOOTSTRAP` themselves, as doing so would subvert the stability guarantees of Rust for your project.\n\ help: If you're sure you want to do this in your project, set the environment variable `RUSTC_BOOTSTRAP={}` before running cargo instead.", val, @@ -665,7 +733,7 @@ if value.is_empty() { value = match flags_iter.next() { Some(v) => v, - None => anyhow::bail! { + None => bail! { "Flag in rustc-flags has no value in {}: {}", whence, value @@ -681,7 +749,7 @@ _ => unreachable!(), }; } else { - anyhow::bail!( + bail!( "Only `-l` and `-L` flags are allowed in {}: `{}`", whence, value @@ -697,7 +765,7 @@ let val = iter.next(); match (name, val) { (Some(n), Some(v)) => Ok((n.to_owned(), v.to_owned())), - _ => anyhow::bail!("Variable rustc-env has no value in {}: {}", whence, value), + _ => bail!("Variable rustc-env has no value in {}: {}", whence, value), } } } @@ -871,8 +939,6 @@ .and_then(|bytes| paths::bytes2path(&bytes)) .unwrap_or_else(|_| script_out_dir.clone()); - let extra_link_arg = cx.bcx.config.cli_unstable().extra_link_arg; - ( BuildOutput::parse_file( &output_file, @@ -880,8 +946,8 @@ &unit.pkg.to_string(), &prev_script_out_dir, &script_out_dir, - extra_link_arg, cx.bcx.config.nightly_features_allowed, + unit.pkg.targets(), ) .ok(), prev_script_out_dir, diff -Nru cargo-0.54.0/src/cargo/core/compiler/fingerprint.rs cargo-0.58.0/src/cargo/core/compiler/fingerprint.rs --- cargo-0.54.0/src/cargo/core/compiler/fingerprint.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/cargo/core/compiler/fingerprint.rs 2021-10-21 14:30:11.000000000 +0000 @@ -315,7 +315,7 @@ use std::collections::hash_map::{Entry, HashMap}; use std::convert::TryInto; use std::env; -use std::hash::{self, Hasher}; +use std::hash::{self, Hash, Hasher}; use std::path::{Path, PathBuf}; use std::str; use std::sync::{Arc, Mutex}; @@ -334,7 +334,7 @@ use crate::util; use crate::util::errors::CargoResult; use crate::util::interning::InternedString; -use crate::util::{internal, path_args, profile}; +use crate::util::{internal, path_args, profile, StableHasher}; use crate::CARGO_ENV; use super::custom_build::BuildDeps; @@ -502,7 +502,7 @@ /// as a fingerprint (all source files must be modified *before* this mtime). /// This dep-info file is not generated, however, until after the crate is /// compiled. As a result, this structure can be thought of as a fingerprint -/// to-be. The actual value can be calculated via `hash()`, but the operation +/// to-be. The actual value can be calculated via `hash_u64()`, but the operation /// may fail as some files may not have been generated. /// /// Note that dependencies are taken into account for fingerprints because rustc @@ -594,7 +594,7 @@ &self.pkg_id, &self.name, &self.public, - &self.fingerprint.hash(), + &self.fingerprint.hash_u64(), ) .serialize(ser) } @@ -782,9 +782,6 @@ } } -#[derive(Debug)] -struct MtimeSlot(Mutex>); - impl Fingerprint { fn new() -> Fingerprint { Fingerprint { @@ -815,7 +812,7 @@ *self.memoized_hash.lock().unwrap() = None; } - fn hash(&self) -> u64 { + fn hash_u64(&self) -> u64 { if let Some(s) = *self.memoized_hash.lock().unwrap() { return s; } @@ -959,13 +956,13 @@ return Err(e); } - if a.fingerprint.hash() != b.fingerprint.hash() { + if a.fingerprint.hash_u64() != b.fingerprint.hash_u64() { let e = format_err!( "new ({}/{:x}) != old ({}/{:x})", a.name, - a.fingerprint.hash(), + a.fingerprint.hash_u64(), b.name, - b.fingerprint.hash() + b.fingerprint.hash_u64() ) .context("unit dependency information changed"); return Err(e); @@ -1148,42 +1145,11 @@ name.hash(h); public.hash(h); // use memoized dep hashes to avoid exponential blowup - h.write_u64(Fingerprint::hash(fingerprint)); + h.write_u64(fingerprint.hash_u64()); } } } -impl hash::Hash for MtimeSlot { - fn hash(&self, h: &mut H) { - self.0.lock().unwrap().hash(h) - } -} - -impl ser::Serialize for MtimeSlot { - fn serialize(&self, s: S) -> Result - where - S: ser::Serializer, - { - self.0 - .lock() - .unwrap() - .map(|ft| (ft.unix_seconds(), ft.nanoseconds())) - .serialize(s) - } -} - -impl<'de> de::Deserialize<'de> for MtimeSlot { - fn deserialize(d: D) -> Result - where - D: de::Deserializer<'de>, - { - let kind: Option<(i64, u32)> = de::Deserialize::deserialize(d)?; - Ok(MtimeSlot(Mutex::new( - kind.map(|(s, n)| FileTime::from_unix_time(s, n)), - ))) - } -} - impl DepFingerprint { fn new(cx: &mut Context<'_, '_>, parent: &Unit, dep: &UnitDep) -> CargoResult { let fingerprint = calculate(cx, &dep.unit)?; @@ -1352,17 +1318,17 @@ // Include metadata since it is exposed as environment variables. let m = unit.pkg.manifest().metadata(); let metadata = util::hash_u64((&m.authors, &m.description, &m.homepage, &m.repository)); - let mut config = 0u64; + let mut config = StableHasher::new(); + if let Some(linker) = cx.bcx.linker(unit.kind) { + linker.hash(&mut config); + } if unit.mode.is_doc() && cx.bcx.config.cli_unstable().rustdoc_map { - config = config.wrapping_add( - cx.bcx - .config - .doc_extern_map() - .map_or(0, |map| util::hash_u64(map)), - ); + if let Ok(map) = cx.bcx.config.doc_extern_map() { + map.hash(&mut config); + } } if let Some(allow_features) = &cx.bcx.config.cli_unstable().allow_features { - config = config.wrapping_add(util::hash_u64(allow_features)); + allow_features.hash(&mut config); } let compile_kind = unit.kind.fingerprint_hash(); Ok(Fingerprint { @@ -1377,7 +1343,7 @@ local: Mutex::new(local), memoized_hash: Mutex::new(None), metadata, - config, + config: config.finish(), compile_kind, rustflags: extra_flags, fs_status: FsStatus::Stale, @@ -1609,14 +1575,14 @@ // fingerprint::new().rustc == 0, make sure it doesn't make it to the file system. // This is mostly so outside tools can reliably find out what rust version this file is for, // as we can use the full hash. - let hash = fingerprint.hash(); + let hash = fingerprint.hash_u64(); debug!("write fingerprint ({:x}) : {}", hash, loc.display()); paths::write(loc, util::to_hex(hash).as_bytes())?; let json = serde_json::to_string(fingerprint).unwrap(); if cfg!(debug_assertions) { let f: Fingerprint = serde_json::from_str(&json).unwrap(); - assert_eq!(f.hash(), hash); + assert_eq!(f.hash_u64(), hash); } paths::write(&loc.with_extension("json"), json.as_bytes())?; Ok(()) @@ -1660,7 +1626,7 @@ paths::set_file_time_no_err(loc, t); } - let new_hash = new_fingerprint.hash(); + let new_hash = new_fingerprint.hash_u64(); if util::to_hex(new_hash) == old_fingerprint_short && new_fingerprint.fs_status.up_to_date() { return Ok(()); @@ -1671,7 +1637,10 @@ .with_context(|| internal("failed to deserialize json"))?; // Fingerprint can be empty after a failed rebuild (see comment in prepare_target). if !old_fingerprint_short.is_empty() { - debug_assert_eq!(util::to_hex(old_fingerprint.hash()), old_fingerprint_short); + debug_assert_eq!( + util::to_hex(old_fingerprint.hash_u64()), + old_fingerprint_short + ); } let result = new_fingerprint.compare(&old_fingerprint); assert!(result.is_err()); diff -Nru cargo-0.54.0/src/cargo/core/compiler/future_incompat.rs cargo-0.58.0/src/cargo/core/compiler/future_incompat.rs --- cargo-0.54.0/src/cargo/core/compiler/future_incompat.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/cargo/core/compiler/future_incompat.rs 2021-10-21 14:30:11.000000000 +0000 @@ -1,4 +1,28 @@ +//! Support for future-incompatible warning reporting. + +use crate::core::{Dependency, PackageId, Workspace}; +use crate::sources::SourceConfigMap; +use crate::util::{iter_join, CargoResult, Config}; +use anyhow::{bail, format_err, Context}; use serde::{Deserialize, Serialize}; +use std::collections::{BTreeSet, HashMap, HashSet}; +use std::fmt::Write as _; +use std::io::{Read, Write}; + +pub const REPORT_PREAMBLE: &str = "\ +The following warnings were discovered during the build. These warnings are an +indication that the packages contain code that will become an error in a +future release of Rust. These warnings typically cover changes to close +soundness problems, unintended or undocumented behavior, or critical problems +that cannot be fixed in a backwards-compatible fashion, and are not expected +to be in wide use. + +Each warning should contain a link for more information on what the warning +means and how to resolve it. +"; + +/// Current version of the on-disk format. +const ON_DISK_VERSION: u32 = 0; /// The future incompatibility report, emitted by the compiler as a JSON message. #[derive(serde::Deserialize)] @@ -6,6 +30,13 @@ pub future_incompat_report: Vec, } +/// Structure used for collecting reports in-memory. +pub struct FutureIncompatReportPackage { + pub package_id: PackageId, + pub items: Vec, +} + +/// A single future-incompatible warning emitted by rustc. #[derive(Serialize, Deserialize)] pub struct FutureBreakageItem { /// The date at which this lint will become an error. @@ -20,17 +51,239 @@ #[derive(Serialize, Deserialize)] pub struct Diagnostic { pub rendered: String, + pub level: String, } /// The filename in the top-level `target` directory where we store /// the report -pub const FUTURE_INCOMPAT_FILE: &str = ".future-incompat-report.json"; +const FUTURE_INCOMPAT_FILE: &str = ".future-incompat-report.json"; +/// Max number of reports to save on disk. +const MAX_REPORTS: usize = 5; +/// The structure saved to disk containing the reports. #[derive(Serialize, Deserialize)] -pub struct OnDiskReport { - // A Cargo-generated id used to detect when a report has been overwritten - pub id: String, - // Cannot be a &str, since Serde needs - // to be able to un-escape the JSON - pub report: String, +pub struct OnDiskReports { + /// A schema version number, to handle older cargo's from trying to read + /// something that they don't understand. + version: u32, + /// The report ID to use for the next report to save. + next_id: u32, + /// Available reports. + reports: Vec, +} + +/// A single report for a given compilation session. +#[derive(Serialize, Deserialize)] +struct OnDiskReport { + /// Unique reference to the report for the `--id` CLI flag. + id: u32, + /// Report, suitable for printing to the console. + report: String, +} + +impl Default for OnDiskReports { + fn default() -> OnDiskReports { + OnDiskReports { + version: ON_DISK_VERSION, + next_id: 1, + reports: Vec::new(), + } + } +} + +impl OnDiskReports { + /// Saves a new report. + pub fn save_report( + ws: &Workspace<'_>, + per_package_reports: &[FutureIncompatReportPackage], + ) -> OnDiskReports { + let mut current_reports = match Self::load(ws) { + Ok(r) => r, + Err(e) => { + log::debug!( + "saving future-incompatible reports failed to load current reports: {:?}", + e + ); + OnDiskReports::default() + } + }; + let report = OnDiskReport { + id: current_reports.next_id, + report: render_report(ws, per_package_reports), + }; + current_reports.next_id += 1; + current_reports.reports.push(report); + if current_reports.reports.len() > MAX_REPORTS { + current_reports.reports.remove(0); + } + let on_disk = serde_json::to_vec(¤t_reports).unwrap(); + if let Err(e) = ws + .target_dir() + .open_rw( + FUTURE_INCOMPAT_FILE, + ws.config(), + "Future incompatibility report", + ) + .and_then(|file| { + let mut file = file.file(); + file.set_len(0)?; + file.write_all(&on_disk)?; + Ok(()) + }) + { + crate::display_warning_with_error( + "failed to write on-disk future incompatible report", + &e, + &mut ws.config().shell(), + ); + } + current_reports + } + + /// Loads the on-disk reports. + pub fn load(ws: &Workspace<'_>) -> CargoResult { + let report_file = match ws.target_dir().open_ro( + FUTURE_INCOMPAT_FILE, + ws.config(), + "Future incompatible report", + ) { + Ok(r) => r, + Err(e) => { + if let Some(io_err) = e.downcast_ref::() { + if io_err.kind() == std::io::ErrorKind::NotFound { + bail!("no reports are currently available"); + } + } + return Err(e); + } + }; + + let mut file_contents = String::new(); + report_file + .file() + .read_to_string(&mut file_contents) + .with_context(|| "failed to read report")?; + let on_disk_reports: OnDiskReports = + serde_json::from_str(&file_contents).with_context(|| "failed to load report")?; + if on_disk_reports.version != ON_DISK_VERSION { + bail!("unable to read reports; reports were saved from a future version of Cargo"); + } + Ok(on_disk_reports) + } + + /// Returns the most recent report ID. + pub fn last_id(&self) -> u32 { + self.reports.last().map(|r| r.id).unwrap() + } + + pub fn get_report(&self, id: u32, config: &Config) -> CargoResult { + let report = self.reports.iter().find(|r| r.id == id).ok_or_else(|| { + let available = iter_join(self.reports.iter().map(|r| r.id.to_string()), ", "); + format_err!( + "could not find report with ID {}\n\ + Available IDs are: {}", + id, + available + ) + })?; + let report = if config.shell().err_supports_color() { + report.report.clone() + } else { + strip_ansi_escapes::strip(&report.report) + .map(|v| String::from_utf8(v).expect("utf8")) + .expect("strip should never fail") + }; + Ok(report) + } +} + +fn render_report( + ws: &Workspace<'_>, + per_package_reports: &[FutureIncompatReportPackage], +) -> String { + let mut per_package_reports: Vec<_> = per_package_reports.iter().collect(); + per_package_reports.sort_by_key(|r| r.package_id); + let mut rendered = String::new(); + for per_package in &per_package_reports { + rendered.push_str(&format!( + "The package `{}` currently triggers the following future \ + incompatibility lints:\n", + per_package.package_id + )); + for item in &per_package.items { + rendered.extend( + item.diagnostic + .rendered + .lines() + .map(|l| format!("> {}\n", l)), + ); + } + rendered.push('\n'); + } + if let Some(s) = render_suggestions(ws, &per_package_reports) { + rendered.push_str(&s); + } + rendered +} + +fn render_suggestions( + ws: &Workspace<'_>, + per_package_reports: &[&FutureIncompatReportPackage], +) -> Option { + // This in general ignores all errors since this is opportunistic. + let _lock = ws.config().acquire_package_cache_lock().ok()?; + // Create a set of updated registry sources. + let map = SourceConfigMap::new(ws.config()).ok()?; + let package_ids: BTreeSet<_> = per_package_reports + .iter() + .map(|r| r.package_id) + .filter(|pkg_id| pkg_id.source_id().is_registry()) + .collect(); + let source_ids: HashSet<_> = package_ids + .iter() + .map(|pkg_id| pkg_id.source_id()) + .collect(); + let mut sources: HashMap<_, _> = source_ids + .into_iter() + .filter_map(|sid| { + let source = map.load(sid, &HashSet::new()).ok()?; + Some((sid, source)) + }) + .collect(); + // Query the sources for new versions. + let mut suggestions = String::new(); + for pkg_id in package_ids { + let source = match sources.get_mut(&pkg_id.source_id()) { + Some(s) => s, + None => continue, + }; + let dep = Dependency::parse(pkg_id.name(), None, pkg_id.source_id()).ok()?; + let summaries = source.query_vec(&dep).ok()?; + let versions = itertools::sorted( + summaries + .iter() + .map(|summary| summary.version()) + .filter(|version| *version > pkg_id.version()), + ); + let versions = versions.map(|version| version.to_string()); + let versions = iter_join(versions, ", "); + if !versions.is_empty() { + writeln!( + suggestions, + "{} has the following newer versions available: {}", + pkg_id, versions + ) + .unwrap(); + } + } + if suggestions.is_empty() { + None + } else { + Some(format!( + "The following packages appear to have newer versions available.\n\ + You may want to consider updating them to a newer version to see if the \ + issue has been fixed.\n\n{}", + suggestions + )) + } } diff -Nru cargo-0.54.0/src/cargo/core/compiler/job_queue.rs cargo-0.58.0/src/cargo/core/compiler/job_queue.rs --- cargo-0.54.0/src/cargo/core/compiler/job_queue.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/cargo/core/compiler/job_queue.rs 2021-10-21 14:30:11.000000000 +0000 @@ -36,7 +36,7 @@ //! //! "NeedsToken" indicates that a rustc is interested in acquiring a token, but //! never that it would be impossible to make progress without one (i.e., it -//! would be incorrect for rustc to not terminate due to a unfulfilled +//! would be incorrect for rustc to not terminate due to an unfulfilled //! NeedsToken request); we do not usually fulfill all NeedsToken requests for a //! given rustc. //! @@ -49,8 +49,9 @@ //! The current scheduling algorithm is relatively primitive and could likely be //! improved. -use std::cell::Cell; -use std::collections::{BTreeMap, HashMap, HashSet}; +use std::cell::{Cell, RefCell}; +use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; +use std::fmt::Write as _; use std::io; use std::marker; use std::sync::Arc; @@ -61,8 +62,7 @@ use crossbeam_utils::thread::Scope; use jobserver::{Acquired, Client, HelperThread}; use log::{debug, info, trace}; -use rand::distributions::Alphanumeric; -use rand::{thread_rng, Rng}; +use semver::Version; use super::context::OutputFile; use super::job::{ @@ -72,10 +72,10 @@ use super::timings::Timings; use super::{BuildContext, BuildPlan, CompileMode, Context, Unit}; use crate::core::compiler::future_incompat::{ - FutureBreakageItem, OnDiskReport, FUTURE_INCOMPAT_FILE, + FutureBreakageItem, FutureIncompatReportPackage, OnDiskReports, }; +use crate::core::resolver::ResolveBehavior; use crate::core::{PackageId, Shell, TargetKind}; -use crate::drop_eprint; use crate::util::diagnostic_server::{self, DiagnosticPrinter}; use crate::util::machine_message::{self, Message as _}; use crate::util::CargoResult; @@ -126,6 +126,14 @@ queue: DependencyQueue, messages: Arc>, + /// Diagnostic deduplication support. + diag_dedupe: DiagDedupe<'cfg>, + /// Count of warnings, used to print a summary after the job succeeds. + /// + /// First value is the total number of warnings, and the second value is + /// the number that were suppressed because they were duplicates of a + /// previous warning. + warning_count: HashMap, active: HashMap, compiled: HashSet, documented: HashSet, @@ -158,7 +166,7 @@ /// How many jobs we've finished finished: usize, - per_crate_future_incompat_reports: Vec, + per_package_future_incompat_reports: Vec, } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] @@ -170,17 +178,12 @@ } } -struct FutureIncompatReportCrate { - package_id: PackageId, - report: Vec, -} - /// A `JobState` is constructed by `JobQueue::run` and passed to `Job::run`. It includes everything /// necessary to communicate between the main thread and the execution of the job. /// /// The job may execute on either a dedicated thread or the main thread. If the job executes on the /// main thread, the `output` field must be set to prevent a deadlock. -pub struct JobState<'a> { +pub struct JobState<'a, 'cfg> { /// Channel back to the main thread to coordinate messages and such. /// /// When the `output` field is `Some`, care must be taken to avoid calling `push_bounded` on @@ -197,7 +200,7 @@ /// interleaved. In the future, it may be wrapped in a `Mutex` instead. In this case /// interleaving is still prevented as the lock would be held for the whole printing of an /// output message. - output: Option<&'a Config>, + output: Option<&'a DiagDedupe<'cfg>>, /// The job id that this state is associated with, used when sending /// messages back to the main thread. @@ -213,6 +216,36 @@ _marker: marker::PhantomData<&'a ()>, } +/// Handler for deduplicating diagnostics. +struct DiagDedupe<'cfg> { + seen: RefCell>, + config: &'cfg Config, +} + +impl<'cfg> DiagDedupe<'cfg> { + fn new(config: &'cfg Config) -> Self { + DiagDedupe { + seen: RefCell::new(HashSet::new()), + config, + } + } + + /// Emits a diagnostic message. + /// + /// Returns `true` if the message was emitted, or `false` if it was + /// suppressed for being a duplicate. + fn emit_diag(&self, diag: &str) -> CargoResult { + let h = util::hash_u64(diag); + if !self.seen.borrow_mut().insert(h) { + return Ok(false); + } + let mut shell = self.config.shell(); + shell.print_ansi_stderr(diag.as_bytes())?; + shell.err().write_all(b"\n")?; + Ok(true) + } +} + /// Possible artifacts that can be produced by compilations, used as edge values /// in the dependency graph. /// @@ -238,6 +271,15 @@ BuildPlanMsg(String, ProcessBuilder, Arc>), Stdout(String), Stderr(String), + Diagnostic { + id: JobId, + level: String, + diag: String, + }, + WarningCount { + id: JobId, + emitted: bool, + }, FixDiagnostic(diagnostic_server::Message), Token(io::Result), Finish(JobId, Artifact, CargoResult<()>), @@ -250,7 +292,7 @@ ReleaseToken(JobId), } -impl<'a> JobState<'a> { +impl<'a, 'cfg> JobState<'a, 'cfg> { pub fn running(&self, cmd: &ProcessBuilder) { self.messages.push(Message::Run(self.id, cmd.to_string())); } @@ -266,8 +308,8 @@ } pub fn stdout(&self, stdout: String) -> CargoResult<()> { - if let Some(config) = self.output { - writeln!(config.shell().out(), "{}", stdout)?; + if let Some(dedupe) = self.output { + writeln!(dedupe.config.shell().out(), "{}", stdout)?; } else { self.messages.push_bounded(Message::Stdout(stdout)); } @@ -275,9 +317,9 @@ } pub fn stderr(&self, stderr: String) -> CargoResult<()> { - if let Some(config) = self.output { - let mut shell = config.shell(); - shell.print_ansi(stderr.as_bytes())?; + if let Some(dedupe) = self.output { + let mut shell = dedupe.config.shell(); + shell.print_ansi_stderr(stderr.as_bytes())?; shell.err().write_all(b"\n")?; } else { self.messages.push_bounded(Message::Stderr(stderr)); @@ -285,6 +327,25 @@ Ok(()) } + pub fn emit_diag(&self, level: String, diag: String) -> CargoResult<()> { + if let Some(dedupe) = self.output { + let emitted = dedupe.emit_diag(&diag)?; + if level == "warning" { + self.messages.push(Message::WarningCount { + id: self.id, + emitted, + }); + } + } else { + self.messages.push_bounded(Message::Diagnostic { + id: self.id, + level, + diag, + }); + } + Ok(()) + } + /// A method used to signal to the coordinator thread that the rmeta file /// for an rlib has been produced. This is only called for some rmeta /// builds when required, and can be called at any time before a job ends. @@ -416,6 +477,8 @@ // typical messages. If you change this, please update the test // caching_large_output, too. messages: Arc::new(Queue::new(100)), + diag_dedupe: DiagDedupe::new(cx.bcx.config), + warning_count: HashMap::new(), active: HashMap::new(), compiled: HashSet::new(), documented: HashSet::new(), @@ -429,7 +492,7 @@ pending_queue: Vec::new(), print: DiagnosticPrinter::new(cx.bcx.config), finished: 0, - per_crate_future_incompat_reports: Vec::new(), + per_package_future_incompat_reports: Vec::new(), }; // Create a helper thread for acquiring jobserver tokens @@ -566,9 +629,18 @@ } Message::Stderr(err) => { let mut shell = cx.bcx.config.shell(); - shell.print_ansi(err.as_bytes())?; + shell.print_ansi_stderr(err.as_bytes())?; shell.err().write_all(b"\n")?; } + Message::Diagnostic { id, level, diag } => { + let emitted = self.diag_dedupe.emit_diag(&diag)?; + if level == "warning" { + self.bump_warning_count(id, emitted); + } + } + Message::WarningCount { id, emitted } => { + self.bump_warning_count(id, emitted); + } Message::FixDiagnostic(msg) => { self.print.print(&msg)?; } @@ -592,6 +664,7 @@ self.tokens.extend(rustc_tokens); } self.to_send_clients.remove(&id); + self.report_warning_count(cx.bcx.config, id); self.active.remove(&id).unwrap() } // ... otherwise if it hasn't finished we leave it @@ -607,14 +680,15 @@ Err(e) => { let msg = "The following warnings were emitted during compilation:"; self.emit_warnings(Some(msg), &unit, cx)?; + self.back_compat_notice(cx, &unit)?; return Err(e); } } } - Message::FutureIncompatReport(id, report) => { + Message::FutureIncompatReport(id, items) => { let package_id = self.active[&id].pkg.package_id(); - self.per_crate_future_incompat_reports - .push(FutureIncompatReportCrate { package_id, report }); + self.per_package_future_incompat_reports + .push(FutureIncompatReportPackage { package_id, items }); } Message::Token(acquired_token) => { let token = acquired_token.with_context(|| "failed to acquire jobserver token")?; @@ -797,7 +871,7 @@ if !cx.bcx.build_config.build_plan { // It doesn't really matter if this fails. drop(cx.bcx.config.shell().status("Finished", message)); - self.emit_future_incompat(cx); + self.emit_future_incompat(cx.bcx); } None @@ -807,93 +881,73 @@ } } - fn emit_future_incompat(&mut self, cx: &mut Context<'_, '_>) { - if cx.bcx.config.cli_unstable().future_incompat_report { - if self.per_crate_future_incompat_reports.is_empty() { + fn emit_future_incompat(&mut self, bcx: &BuildContext<'_, '_>) { + if !bcx.config.cli_unstable().future_incompat_report { + return; + } + let should_display_message = match bcx.config.future_incompat_config() { + Ok(config) => config.should_display_message(), + Err(e) => { + crate::display_warning_with_error( + "failed to read future-incompat config from disk", + &e, + &mut bcx.config.shell(), + ); + true + } + }; + + if self.per_package_future_incompat_reports.is_empty() { + // Explicitly passing a command-line flag overrides + // `should_display_message` from the config file + if bcx.build_config.future_incompat_report { drop( - cx.bcx - .config + bcx.config .shell() - .note("0 dependencies had future-incompat warnings"), + .note("0 dependencies had future-incompatible warnings"), ); - return; } - self.per_crate_future_incompat_reports - .sort_by_key(|r| r.package_id); + return; + } - let crates_and_versions = self - .per_crate_future_incompat_reports - .iter() - .map(|r| r.package_id.to_string()) - .collect::>() - .join(", "); - - drop(cx.bcx.config.shell().warn(&format!( - "the following crates contain code that will be rejected by a future version of Rust: {}", - crates_and_versions + // Get a list of unique and sorted package name/versions. + let package_vers: BTreeSet<_> = self + .per_package_future_incompat_reports + .iter() + .map(|r| r.package_id) + .collect(); + let package_vers: Vec<_> = package_vers + .into_iter() + .map(|pid| pid.to_string()) + .collect(); + + if should_display_message || bcx.build_config.future_incompat_report { + drop(bcx.config.shell().warn(&format!( + "the following packages contain code that will be rejected by a future \ + version of Rust: {}", + package_vers.join(", ") ))); + } - let mut full_report = String::new(); - let mut rng = thread_rng(); - - // Generate a short ID to allow detecting if a report gets overwritten - let id: String = std::iter::repeat(()) - .map(|()| char::from(rng.sample(Alphanumeric))) - .take(4) - .collect(); - - for report in std::mem::take(&mut self.per_crate_future_incompat_reports) { - full_report.push_str(&format!( - "The crate `{}` currently triggers the following future incompatibility lints:\n", - report.package_id - )); - for item in report.report { - let rendered = if cx.bcx.config.shell().err_supports_color() { - item.diagnostic.rendered - } else { - strip_ansi_escapes::strip(&item.diagnostic.rendered) - .map(|v| String::from_utf8(v).expect("utf8")) - .expect("strip should never fail") - }; - - for line in rendered.lines() { - full_report.push_str(&format!("> {}\n", line)); - } - } - } - - let report_file = cx.bcx.ws.target_dir().open_rw( - FUTURE_INCOMPAT_FILE, - cx.bcx.config, - "Future incompatibility report", - ); - let err = report_file - .and_then(|report_file| { - let on_disk_report = OnDiskReport { - id: id.clone(), - report: full_report.clone(), - }; - serde_json::to_writer(report_file, &on_disk_report).map_err(|e| e.into()) - }) - .err(); - if let Some(e) = err { - crate::display_warning_with_error( - "failed to write on-disk future incompat report", - &e, - &mut cx.bcx.config.shell(), - ); - } - - 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) - )); - } 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) - )); - } + let on_disk_reports = + OnDiskReports::save_report(bcx.ws, &self.per_package_future_incompat_reports); + let report_id = on_disk_reports.last_id(); + + if bcx.build_config.future_incompat_report { + let rendered = on_disk_reports.get_report(report_id, bcx.config).unwrap(); + drop(bcx.config.shell().print_ansi_stderr(rendered.as_bytes())); + drop(bcx.config.shell().note(&format!( + "this report can be shown with `cargo report \ + future-incompatibilities -Z future-incompat-report --id {}`", + report_id + ))); + } else if should_display_message { + drop(bcx.config.shell().note(&format!( + "to see what the problems were, use the option \ + `--future-incompat-report`, or run `cargo report \ + future-incompatibilities --id {}`", + report_id + ))); } } @@ -944,20 +998,30 @@ fn name_for_progress(&self, unit: &Unit) -> String { let pkg_name = unit.pkg.name(); + let target_name = unit.target.name(); match unit.mode { CompileMode::Doc { .. } => format!("{}(doc)", pkg_name), CompileMode::RunCustomBuild => format!("{}(build)", pkg_name), - _ => { - let annotation = match unit.target.kind() { - TargetKind::Lib(_) => return pkg_name.to_string(), - TargetKind::CustomBuild => return format!("{}(build.rs)", pkg_name), - TargetKind::Bin => "bin", - TargetKind::Test => "test", - TargetKind::Bench => "bench", - TargetKind::ExampleBin | TargetKind::ExampleLib(_) => "example", - }; - format!("{}({})", unit.target.name(), annotation) - } + CompileMode::Test | CompileMode::Check { test: true } => match unit.target.kind() { + TargetKind::Lib(_) => format!("{}(test)", target_name), + TargetKind::CustomBuild => panic!("cannot test build script"), + TargetKind::Bin => format!("{}(bin test)", target_name), + TargetKind::Test => format!("{}(test)", target_name), + TargetKind::Bench => format!("{}(bench)", target_name), + TargetKind::ExampleBin | TargetKind::ExampleLib(_) => { + format!("{}(example test)", target_name) + } + }, + _ => match unit.target.kind() { + TargetKind::Lib(_) => pkg_name.to_string(), + TargetKind::CustomBuild => format!("{}(build.rs)", pkg_name), + TargetKind::Bin => format!("{}(bin)", target_name), + TargetKind::Test => format!("{}(test)", target_name), + TargetKind::Bench => format!("{}(bench)", target_name), + TargetKind::ExampleBin | TargetKind::ExampleLib(_) => { + format!("{}(example)", target_name) + } + }, } } @@ -977,7 +1041,7 @@ let fresh = job.freshness(); let rmeta_required = cx.rmeta_required(unit); - let doit = move |state: JobState<'_>| { + let doit = move |state: JobState<'_, '_>| { let mut sender = FinishOnDrop { messages: &state.messages, id, @@ -1033,7 +1097,7 @@ doit(JobState { id, messages, - output: Some(cx.bcx.config), + output: Some(&self.diag_dedupe), rmeta_required: Cell::new(rmeta_required), _marker: marker::PhantomData, }); @@ -1085,6 +1149,44 @@ Ok(()) } + fn bump_warning_count(&mut self, id: JobId, emitted: bool) { + let cnts = self.warning_count.entry(id).or_default(); + cnts.0 += 1; + if !emitted { + cnts.1 += 1; + } + } + + /// Displays a final report of the warnings emitted by a particular job. + fn report_warning_count(&mut self, config: &Config, id: JobId) { + let count = match self.warning_count.remove(&id) { + Some(count) => count, + None => return, + }; + let unit = &self.active[&id]; + let mut message = format!("`{}` ({}", unit.pkg.name(), unit.target.description_named()); + if unit.mode.is_rustc_test() && !(unit.target.is_test() || unit.target.is_bench()) { + message.push_str(" test"); + } else if unit.mode.is_doc_test() { + message.push_str(" doctest"); + } else if unit.mode.is_doc() { + message.push_str(" doc"); + } + message.push_str(") generated "); + match count.0 { + 1 => message.push_str("1 warning"), + n => drop(write!(message, "{} warnings", n)), + }; + match count.1 { + 0 => {} + 1 => message.push_str(" (1 duplicate)"), + n => drop(write!(message, " ({} duplicates)", n)), + } + // Errors are ignored here because it is tricky to handle them + // correctly, and they aren't important. + drop(config.shell().warn(message)); + } + fn finish( &mut self, id: JobId, @@ -1154,4 +1256,30 @@ } Ok(()) } + + fn back_compat_notice(&self, cx: &Context<'_, '_>, unit: &Unit) -> CargoResult<()> { + if unit.pkg.name() != "diesel" + || unit.pkg.version() >= &Version::new(1, 4, 8) + || cx.bcx.ws.resolve_behavior() == ResolveBehavior::V1 + || !unit.pkg.package_id().source_id().is_registry() + || !unit.features.is_empty() + { + return Ok(()); + } + if !cx + .bcx + .unit_graph + .keys() + .any(|unit| unit.pkg.name() == "diesel" && !unit.features.is_empty()) + { + return Ok(()); + } + cx.bcx.config.shell().note( + "\ +This error may be due to an interaction between diesel and Cargo's new +feature resolver. Try updating to diesel 1.4.8 to fix this error. +", + )?; + Ok(()) + } } diff -Nru cargo-0.54.0/src/cargo/core/compiler/job.rs cargo-0.58.0/src/cargo/core/compiler/job.rs --- cargo-0.54.0/src/cargo/core/compiler/job.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/cargo/core/compiler/job.rs 2021-10-21 14:30:11.000000000 +0000 @@ -12,13 +12,13 @@ /// Each proc should send its description before starting. /// It should send either once or close immediately. pub struct Work { - inner: Box) -> CargoResult<()> + Send>, + inner: Box) -> CargoResult<()> + Send>, } impl Work { pub fn new(f: F) -> Work where - F: FnOnce(&JobState<'_>) -> CargoResult<()> + Send + 'static, + F: FnOnce(&JobState<'_, '_>) -> CargoResult<()> + Send + 'static, { Work { inner: Box::new(f) } } @@ -27,7 +27,7 @@ Work::new(|_| Ok(())) } - pub fn call(self, tx: &JobState<'_>) -> CargoResult<()> { + pub fn call(self, tx: &JobState<'_, '_>) -> CargoResult<()> { (self.inner)(tx) } @@ -58,7 +58,7 @@ /// Consumes this job by running it, returning the result of the /// computation. - pub fn run(self, state: &JobState<'_>) -> CargoResult<()> { + pub fn run(self, state: &JobState<'_, '_>) -> CargoResult<()> { self.work.call(state) } diff -Nru cargo-0.54.0/src/cargo/core/compiler/layout.rs cargo-0.58.0/src/cargo/core/compiler/layout.rs --- cargo-0.54.0/src/cargo/core/compiler/layout.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/cargo/core/compiler/layout.rs 2021-10-21 14:30:11.000000000 +0000 @@ -125,6 +125,8 @@ 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 @@ fingerprint: dest.join(".fingerprint"), examples: dest.join("examples"), doc: root.join("doc"), + tmp: root.join("tmp"), root, dest, _lock: lock, @@ -219,4 +222,9 @@ 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) + } } diff -Nru cargo-0.54.0/src/cargo/core/compiler/links.rs cargo-0.58.0/src/cargo/core/compiler/links.rs --- cargo-0.54.0/src/cargo/core/compiler/links.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/cargo/core/compiler/links.rs 2021-10-21 14:30:11.000000000 +0000 @@ -1,8 +1,8 @@ use super::unit_graph::UnitGraph; +use crate::core::resolver::errors::describe_path; use crate::core::{PackageId, Resolve}; use crate::util::errors::CargoResult; use std::collections::{HashMap, HashSet}; -use std::fmt::Write; /// Validate `links` field does not conflict between packages. pub fn validate_links(resolve: &Resolve, unit_graph: &UnitGraph) -> CargoResult<()> { @@ -28,17 +28,15 @@ None => continue, }; if let Some(&prev) = links.get(lib) { + let prev_path = resolve + .path_to_top(&prev) + .into_iter() + .map(|(p, d)| (p, d.and_then(|d| d.iter().next()))); let pkg = unit.pkg.package_id(); - - let describe_path = |pkgid: PackageId| -> String { - let dep_path = resolve.path_to_top(&pkgid); - let mut dep_path_desc = format!("package `{}`", dep_path[0]); - for dep in dep_path.iter().skip(1) { - write!(dep_path_desc, "\n ... which is depended on by `{}`", dep).unwrap(); - } - dep_path_desc - }; - + let path = resolve + .path_to_top(&pkg) + .into_iter() + .map(|(p, d)| (p, d.and_then(|d| d.iter().next()))); anyhow::bail!( "multiple packages link to native library `{}`, \ but a native library can be linked only once\n\ @@ -47,9 +45,9 @@ \n\ {}\nalso links to native library `{}`", lib, - describe_path(prev), + describe_path(prev_path), lib, - describe_path(pkg), + describe_path(path), lib ) } diff -Nru cargo-0.54.0/src/cargo/core/compiler/mod.rs cargo-0.58.0/src/cargo/core/compiler/mod.rs --- cargo-0.54.0/src/cargo/core/compiler/mod.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/cargo/core/compiler/mod.rs 2021-10-21 14:30:11.000000000 +0000 @@ -62,29 +62,27 @@ const RUSTDOC_CRATE_VERSION_FLAG: &str = "--crate-version"; -#[derive(Copy, Clone, Hash, Debug, PartialEq, Eq)] +#[derive(Clone, Hash, Debug, PartialEq, Eq)] pub enum LinkType { + All, Cdylib, Bin, + SingleBin(String), Test, Bench, Example, } -impl From<&super::Target> for Option { - fn from(value: &super::Target) -> Self { - if value.is_cdylib() { - Some(LinkType::Cdylib) - } else if value.is_bin() { - Some(LinkType::Bin) - } else if value.is_test() { - Some(LinkType::Test) - } else if value.is_bench() { - Some(LinkType::Bench) - } else if value.is_exe_example() { - Some(LinkType::Example) - } else { - None +impl LinkType { + pub fn applies_to(&self, target: &Target) -> bool { + match self { + LinkType::All => true, + LinkType::Cdylib => target.is_cdylib(), + LinkType::Bin => target.is_bin(), + LinkType::SingleBin(name) => target.is_bin() && target.name() == name, + LinkType::Test => target.is_test(), + LinkType::Bench => target.is_bench(), + LinkType::Example => target.is_exe_example(), } } } @@ -227,7 +225,6 @@ // If we are a binary and the package also contains a library, then we // don't pass the `-l` flags. let pass_l_flag = unit.target.is_lib() || !unit.pkg.targets().iter().any(|t| t.is_lib()); - let link_type = (&unit.target).into(); let dep_info_name = if cx.files().use_extra_filename(unit) { format!( @@ -280,7 +277,7 @@ &script_outputs, &build_scripts, pass_l_flag, - link_type, + &target, current_id, )?; add_plugin_deps(&mut rustc, &script_outputs, &build_scripts, &root_output)?; @@ -336,7 +333,22 @@ }, ) .map_err(verbose_if_simple_exit_code) - .with_context(|| format!("could not compile `{}`", name))?; + .with_context(|| { + // adapted from rustc_errors/src/lib.rs + let warnings = match output_options.warnings_seen { + 0 => String::new(), + 1 => "; 1 warning emitted".to_string(), + count => format!("; {} warnings emitted", count), + }; + let errors = match output_options.errors_seen { + 0 => String::new(), + 1 => " due to previous error".to_string(), + count => format!(" due to {} previous errors", count), + }; + format!("could not compile `{}`{}{}", name, errors, warnings) + })?; + // Exec should never return with success *and* generate an error. + debug_assert_eq!(output_options.errors_seen, 0); } if rustc_dep_info_loc.exists() { @@ -371,7 +383,7 @@ build_script_outputs: &BuildScriptOutputs, build_scripts: &BuildScripts, pass_l_flag: bool, - link_type: Option, + target: &Target, current_id: PackageId, ) -> CargoResult<()> { for key in build_scripts.to_link.iter() { @@ -396,11 +408,14 @@ } } - if link_type.is_some() { - for (lt, arg) in &output.linker_args { - if lt.is_none() || *lt == link_type { - rustc.arg("-C").arg(format!("link-arg={}", arg)); - } + for (lt, arg) in &output.linker_args { + // There was an unintentional change where cdylibs were + // allowed to be passed via transitive dependencies. This + // clause should have been kept in the `if` block above. For + // now, continue allowing it for cdylib only. + // See https://github.com/rust-lang/cargo/issues/9562 + if lt.applies_to(target) && (key.0 == current_id || *lt == LinkType::Cdylib) { + rustc.arg("-C").arg(format!("link-arg={}", arg)); } } } @@ -581,6 +596,11 @@ 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); @@ -776,6 +796,7 @@ let bcx = cx.bcx; let Profile { ref opt_level, + codegen_backend, codegen_units, debuginfo, debug_assertions, @@ -840,6 +861,10 @@ } } + if let Some(backend) = codegen_backend { + cmd.arg("-Z").arg(&format!("codegen-backend={}", backend)); + } + if let Some(n) = codegen_units { cmd.arg("-C").arg(&format!("codegen-units={}", n)); } @@ -960,7 +985,10 @@ let exe_path = cx .files() .bin_link_for_target(bin_target, unit.kind, cx.bcx)?; - let key = format!("CARGO_BIN_EXE_{}", bin_target.name()); + let name = bin_target + .binary_filename() + .unwrap_or(bin_target.name().to_string()); + let key = format!("CARGO_BIN_EXE_{}", name); cmd.env(&key, exe_path); } } @@ -1152,10 +1180,16 @@ /// of empty files are not created. If this is None, the output will not /// be cached (such as when replaying cached messages). cache_cell: Option<(PathBuf, LazyCell)>, - /// If `true`, display any recorded warning messages. - /// Other types of messages are processed regardless - /// of the value of this flag - show_warnings: bool, + /// If `true`, display any diagnostics. + /// Other types of JSON messages are processed regardless + /// of the value of this flag. + /// + /// This is used primarily for cache replay. If you build with `-vv`, the + /// cache will be filled with diagnostics from dependencies. When the + /// cache is replayed without `-vv`, we don't want to show them. + show_diagnostics: bool, + warnings_seen: usize, + errors_seen: usize, } impl OutputOptions { @@ -1171,13 +1205,15 @@ look_for_metadata_directive, color, cache_cell, - show_warnings: true, + show_diagnostics: true, + warnings_seen: 0, + errors_seen: 0, } } } fn on_stdout_line( - state: &JobState<'_>, + state: &JobState<'_, '_>, line: &str, _package_id: PackageId, _target: &Target, @@ -1187,7 +1223,7 @@ } fn on_stderr_line( - state: &JobState<'_>, + state: &JobState<'_, '_>, line: &str, package_id: PackageId, manifest_path: &std::path::Path, @@ -1209,7 +1245,7 @@ /// Returns true if the line should be cached. fn on_stderr_line_inner( - state: &JobState<'_>, + state: &JobState<'_, '_>, line: &str, package_id: PackageId, manifest_path: &std::path::Path, @@ -1239,7 +1275,18 @@ } }; + let count_diagnostic = |level, options: &mut OutputOptions| { + if level == "warning" { + options.warnings_seen += 1; + } else if level == "error" { + options.errors_seen += 1; + } + }; + if let Ok(report) = serde_json::from_str::(compiler_message.get()) { + for item in &report.future_incompat_report { + count_diagnostic(&*item.diagnostic.level, options); + } state.future_incompat_report(report.future_incompat_report); return Ok(true); } @@ -1260,23 +1307,33 @@ #[derive(serde::Deserialize)] struct CompilerMessage { rendered: String, + message: String, + level: String, } - if let Ok(mut error) = serde_json::from_str::(compiler_message.get()) { + if let Ok(mut msg) = serde_json::from_str::(compiler_message.get()) { + if msg.message.starts_with("aborting due to") + || msg.message.ends_with("warning emitted") + || msg.message.ends_with("warnings emitted") + { + // Skip this line; we'll print our own summary at the end. + return Ok(true); + } // state.stderr will add a newline - if error.rendered.ends_with('\n') { - error.rendered.pop(); + if msg.rendered.ends_with('\n') { + msg.rendered.pop(); } let rendered = if options.color { - error.rendered + msg.rendered } else { // Strip only fails if the the Writer fails, which is Cursor // on a Vec, which should never fail. - strip_ansi_escapes::strip(&error.rendered) + strip_ansi_escapes::strip(&msg.rendered) .map(|v| String::from_utf8(v).expect("utf8")) .expect("strip should never fail") }; - if options.show_warnings { - state.stderr(rendered)?; + if options.show_diagnostics { + count_diagnostic(&msg.level, options); + state.emit_diag(msg.level, rendered)?; } return Ok(true); } @@ -1359,10 +1416,18 @@ // from the compiler, so wrap it in an external Cargo JSON message // indicating which package it came from and then emit it. - if !options.show_warnings { + if !options.show_diagnostics { return Ok(true); } + #[derive(serde::Deserialize)] + struct CompilerMessage { + level: String, + } + if let Ok(message) = serde_json::from_str::(compiler_message.get()) { + count_diagnostic(&message.level, options); + } + let msg = machine_message::FromCompiler { package_id, manifest_path, @@ -1385,7 +1450,7 @@ path: PathBuf, format: MessageFormat, color: bool, - show_warnings: bool, + show_diagnostics: bool, ) -> Work { let target = target.clone(); let mut options = OutputOptions { @@ -1393,7 +1458,9 @@ look_for_metadata_directive: true, color, cache_cell: None, - show_warnings, + show_diagnostics, + warnings_seen: 0, + errors_seen: 0, }; Work::new(move |state| { if !path.exists() { diff -Nru cargo-0.54.0/src/cargo/core/compiler/output_depinfo.rs cargo-0.58.0/src/cargo/core/compiler/output_depinfo.rs --- cargo-0.54.0/src/cargo/core/compiler/output_depinfo.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/cargo/core/compiler/output_depinfo.rs 2021-10-21 14:30:11.000000000 +0000 @@ -81,7 +81,10 @@ if let Some(metadata) = cx.find_build_script_metadata(unit) { if let Some(output) = cx.build_script_outputs.lock().unwrap().get(metadata) { for path in &output.rerun_if_changed { - deps.insert(path.into()); + // The paths we have saved from the unit are of arbitrary relativeness and may be + // relative to the crate root of the dependency. + let path = unit.pkg.root().join(path); + deps.insert(path); } } } @@ -89,7 +92,7 @@ // Recursively traverse all transitive dependencies let unit_deps = Vec::from(cx.unit_deps(unit)); // Create vec due to mutable borrow. for dep in unit_deps { - if unit.is_local() { + if dep.unit.is_local() { add_deps_for_unit(deps, cx, &dep.unit, visited)?; } } diff -Nru cargo-0.54.0/src/cargo/core/compiler/rustdoc.rs cargo-0.58.0/src/cargo/core/compiler/rustdoc.rs --- cargo-0.54.0/src/cargo/core/compiler/rustdoc.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/cargo/core/compiler/rustdoc.rs 2021-10-21 14:30:11.000000000 +0000 @@ -11,6 +11,8 @@ use std::hash; use url::Url; +const DOCS_RS_URL: &'static str = "https://docs.rs/"; + /// Mode used for `std`. #[derive(Debug, Hash)] pub enum RustdocExternMode { @@ -63,7 +65,7 @@ impl Default for RustdocExternMap { fn default() -> Self { let mut registries = HashMap::new(); - registries.insert("crates-io".into(), "https://docs.rs/".into()); + registries.insert(CRATES_IO_REGISTRY.into(), DOCS_RS_URL.into()); Self { registries, std: None, @@ -76,8 +78,8 @@ ) -> Result, D::Error> { use serde::Deserialize; let mut registries = HashMap::deserialize(de)?; - if !registries.contains_key("crates-io") { - registries.insert("crates-io".into(), "https://docs.rs/".into()); + if !registries.contains_key(CRATES_IO_REGISTRY) { + registries.insert(CRATES_IO_REGISTRY.into(), DOCS_RS_URL.into()); } Ok(registries) } diff -Nru cargo-0.54.0/src/cargo/core/compiler/standard_lib.rs cargo-0.58.0/src/cargo/core/compiler/standard_lib.rs --- cargo-0.54.0/src/cargo/core/compiler/standard_lib.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/cargo/core/compiler/standard_lib.rs 2021-10-21 14:30:11.000000000 +0000 @@ -47,7 +47,7 @@ .iter() .map(|&name| { let source_path = SourceId::for_path(&src_path.join("library").join(name))?; - let dep = Dependency::parse_no_deprecated(name, None, source_path)?; + let dep = Dependency::parse(name, None, source_path)?; Ok(dep) }) .collect::>>()?; @@ -200,11 +200,19 @@ .join("rust"); let lock = src_path.join("Cargo.lock"); if !lock.exists() { - anyhow::bail!( + let msg = format!( "{:?} does not exist, unable to build with the standard \ library, try:\n rustup component add rust-src", lock ); + match env::var("RUSTUP_TOOLCHAIN") { + Ok(rustup_toolchain) => { + anyhow::bail!("{} --toolchain {}", msg, rustup_toolchain); + } + Err(_) => { + anyhow::bail!(msg); + } + } } Ok(src_path) } diff -Nru cargo-0.54.0/src/cargo/core/compiler/timings.rs cargo-0.58.0/src/cargo/core/compiler/timings.rs --- cargo-0.54.0/src/cargo/core/compiler/timings.rs 2021-04-27 14:35:53.000000000 +0000 +++ cargo-0.58.0/src/cargo/core/compiler/timings.rs 2021-10-21 14:30:11.000000000 +0000 @@ -529,7 +529,7 @@ target: ut.target.clone(), start: round(ut.start), duration: round(ut.duration), - rmeta_time: ut.rmeta_time.map(|t| round(t)), + rmeta_time: ut.rmeta_time.map(round), unlocked_units, unlocked_rmeta_units, } @@ -643,7 +643,7 @@ static HTML_TMPL: &str = r#" - Cargo Build Timings — {ROOTS} + Cargo Build Timings — {ROOTS}