diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:42 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:42 +0000 |
commit | 837b550238aa671a591ccf282dddeab29cadb206 (patch) | |
tree | 914b6b8862bace72bd3245ca184d374b08d8a672 /src/tools/cargo | |
parent | Adding debian version 1.70.0+dfsg2-1. (diff) | |
download | rustc-837b550238aa671a591ccf282dddeab29cadb206.tar.xz rustc-837b550238aa671a591ccf282dddeab29cadb206.zip |
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tools/cargo')
286 files changed, 11952 insertions, 2001 deletions
diff --git a/src/tools/cargo/.cargo/config.toml b/src/tools/cargo/.cargo/config.toml new file mode 100644 index 000000000..c4a595b61 --- /dev/null +++ b/src/tools/cargo/.cargo/config.toml @@ -0,0 +1,4 @@ +[alias] +build-man = "run --package xtask-build-man --" +stale-label = "run --package xtask-stale-label --" +unpublished = "run --package xtask-unpublished --" diff --git a/src/tools/cargo/.github/ISSUE_TEMPLATE/bug_report.yml b/src/tools/cargo/.github/ISSUE_TEMPLATE/bug_report.yml index f465e1240..5cee9c65c 100644 --- a/src/tools/cargo/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/src/tools/cargo/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,6 +1,6 @@ name: Bug Report description: Create a report to help us improve -labels: ["C-bug"] +labels: ["C-bug", "S-triage"] body: - type: markdown attributes: diff --git a/src/tools/cargo/.github/ISSUE_TEMPLATE/feature_request.yml b/src/tools/cargo/.github/ISSUE_TEMPLATE/feature_request.yml index bae2469d1..e6ed547f8 100644 --- a/src/tools/cargo/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/src/tools/cargo/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,6 +1,6 @@ name: Feature Request description: Suggest an idea for enhancing Cargo -labels: ["C-feature-request"] +labels: ["C-feature-request", "S-triage"] body: - type: markdown attributes: diff --git a/src/tools/cargo/.github/workflows/main.yml b/src/tools/cargo/.github/workflows/main.yml index 400e725e5..c522a19a1 100644 --- a/src/tools/cargo/.github/workflows/main.yml +++ b/src/tools/cargo/.github/workflows/main.yml @@ -24,12 +24,6 @@ jobs: - run: rustup update stable && rustup default stable - run: rustup component add rustfmt - run: cargo fmt --all --check - - run: | - for manifest in `find crates benches/benchsuite benches/capture -name Cargo.toml` - do - echo check fmt for $manifest - cargo fmt --all --manifest-path $manifest --check - done # Ensure there are no clippy warnings clippy: @@ -39,7 +33,35 @@ jobs: - run: rustup update stable && rustup default stable - run: rustup component add clippy # Only check cargo lib for now - - run: cargo clippy -p cargo --lib -- -D warnings + # TODO: check every members + - run: cargo clippy -p cargo --lib --no-deps -- -D warnings + + stale-label: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: rustup update stable && rustup default stable + - run: cargo stale-label + + # Ensure Cargo.lock is up-to-date + lockfile: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: rustup update stable && rustup default stable + - run: cargo update -p cargo --locked + + check-version-bump: + runs-on: ubuntu-latest + env: + BASE_SHA: ${{ github.event.pull_request.base.sha }} + HEAD_SHA: ${{ github.sha }} + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # make `git diff` work + - run: rustup update stable && rustup default stable + - run: ci/validate-version-bump.sh test: runs-on: ${{ matrix.os }} @@ -101,47 +123,39 @@ jobs: run: echo CARGO_CONTAINER_TESTS=1 >> $GITHUB_ENV if: matrix.os == 'ubuntu-latest' - - run: cargo test + - run: cargo test -p cargo - name: Clear intermediate test output run: ci/clean-test-output.sh - name: gitoxide tests (all git-related tests) - run: cargo test git + run: cargo test -p cargo git env: __CARGO_USE_GITOXIDE_INSTEAD_OF_GIT2: 1 # The testsuite generates a huge amount of data, and fetch-smoke-test was # running out of disk space. - name: Clear test output run: ci/clean-test-output.sh + # This only tests `cargo fix` because fix-proxy-mode is one of the most + # complicated subprocess management in Cargo. - name: Check operability of rustc invocation with argfile + run: 'cargo test -p cargo --test testsuite -- fix::' env: __CARGO_TEST_FORCE_ARGFILE: 1 - run: | - # This only tests `cargo fix` because fix-proxy-mode is one of the most - # complicated subprocess management in Cargo. - cargo test --test testsuite -- fix:: - - run: cargo test --manifest-path crates/cargo-test-support/Cargo.toml - env: - CARGO_TARGET_DIR: target + - run: cargo test -p cargo-test-support - run: cargo test -p cargo-platform - run: cargo test -p cargo-util - - run: cargo test --manifest-path crates/home/Cargo.toml - - run: cargo test --manifest-path crates/mdman/Cargo.toml - - run: cargo build --manifest-path crates/credential/cargo-credential-1password/Cargo.toml - - run: cargo build --manifest-path crates/credential/cargo-credential-gnome-secret/Cargo.toml + - run: cargo test -p home + - run: cargo test -p mdman + - run: cargo build -p cargo-credential-1password + - run: cargo build -p cargo-credential-macos-keychain + - run: cargo build -p cargo-credential-wincred + - run: cargo build -p cargo-credential-gnome-secret if: matrix.os == 'ubuntu-latest' - - run: cargo build --manifest-path crates/credential/cargo-credential-macos-keychain/Cargo.toml - if: matrix.os == 'macos-latest' - - run: cargo build --manifest-path crates/credential/cargo-credential-wincred/Cargo.toml - if: matrix.os == 'windows-latest' - name: Check benchmarks - env: - # Share the target dir to try to cache a few build-time deps. - CARGO_TARGET_DIR: target run: | # This only tests one benchmark since it can take over 10 minutes to # download all workspaces. - cargo test --manifest-path benches/benchsuite/Cargo.toml --all-targets -- cargo - cargo check --manifest-path benches/capture/Cargo.toml + cargo test -p benchsuite --all-targets -- cargo + cargo check -p capture # The testsuite generates a huge amount of data, and fetch-smoke-test was # running out of disk space. - name: Clear benchmark output @@ -154,7 +168,7 @@ jobs: steps: - uses: actions/checkout@v3 - run: rustup update stable && rustup default stable - - run: cargo test --manifest-path crates/resolver-tests/Cargo.toml + - run: cargo test -p resolver-tests test_gitoxide: runs-on: ubuntu-latest @@ -164,7 +178,7 @@ jobs: - run: rustup target add i686-unknown-linux-gnu - run: sudo apt update -y && sudo apt install gcc-multilib libsecret-1-0 libsecret-1-dev -y - run: rustup component add rustfmt || echo "rustfmt not available" - - run: cargo test + - run: cargo test -p cargo env: __CARGO_USE_GITOXIDE_INSTEAD_OF_GIT2: 1 @@ -175,7 +189,7 @@ jobs: - run: rustup update nightly && rustup default nightly - run: rustup component add rust-src - run: cargo build - - run: cargo test --test build-std + - run: cargo test -p cargo --test build-std env: CARGO_RUN_BUILD_STD_TESTS: 1 docs: @@ -187,26 +201,36 @@ jobs: - run: rustup component add rust-docs - run: ci/validate-man.sh # This requires rustfmt, use stable. - - run: cd src/doc/semver-check && cargo +stable run - - run: | + - name: Run semver-check + run: cargo +stable run -p semver-check + - name: Ensure intradoc links are valid + run: cargo doc --workspace --document-private-items --no-deps + env: + RUSTDOCFLAGS: -D warnings + - name: Install mdbook + run: | mkdir mdbook curl -Lf https://github.com/rust-lang/mdBook/releases/download/v0.4.27/mdbook-v0.4.27-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook echo `pwd`/mdbook >> $GITHUB_PATH - - run: cargo doc --document-private-items --no-deps - env: - RUSTDOCFLAGS: -D warnings - run: cd src/doc && mdbook build --dest-dir ../../target/doc - - run: | - cd src/doc - curl -sSLo linkcheck.sh \ - https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/linkcheck.sh - sh linkcheck.sh --all cargo + - name: Run linkchecker.sh + run: | + cd target + curl -sSLO https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/linkcheck.sh + sh linkcheck.sh --all --path ../src/doc cargo success: permissions: contents: none name: bors build finished - needs: [docs, rustfmt, test, resolver, build_std, test_gitoxide] + needs: + - build_std + - docs + - lockfile + - resolver + - rustfmt + - test + - test_gitoxide runs-on: ubuntu-latest if: "success() && github.event_name == 'push' && github.ref == 'refs/heads/auto-cargo'" steps: @@ -215,7 +239,14 @@ jobs: permissions: contents: none name: bors build finished - needs: [docs, rustfmt, test, resolver, build_std] + needs: + - build_std + - docs + - lockfile + - resolver + - rustfmt + - test + - test_gitoxide runs-on: ubuntu-latest if: "!success() && github.event_name == 'push' && github.ref == 'refs/heads/auto-cargo'" steps: diff --git a/src/tools/cargo/CHANGELOG.md b/src/tools/cargo/CHANGELOG.md index a3d488d92..5cb4d11c5 100644 --- a/src/tools/cargo/CHANGELOG.md +++ b/src/tools/cargo/CHANGELOG.md @@ -1,12 +1,75 @@ # Changelog +## Cargo 1.71 (2023-07-13) +[84b7041f...HEAD](https://github.com/rust-lang/cargo/compare/84b7041f...HEAD) + +### Added + +### Changed + +- ❗ Optimized the usage under `rustup`. When Cargo detects it will run `rustc` + pointing a rustup proxy, it'll try bypassing the proxy and use the underlying + binary directly. There are assumptions around the interaction with rustup and + `RUSTUP_TOOLCHAIN`. However, it's not expected to affect normal users. + [#11917](https://github.com/rust-lang/cargo/pull/11917) +- ❗ When querying a package, Cargo tries only the original name, all hyphens, + and all underscores to handle misspellings. Previously, Cargo tried each + combination of hyphens and underscores, causing excessive requests to crates.io. + [#12083](https://github.com/rust-lang/cargo/pull/12083) +- ❗ Disallow `RUSTUP_HOME` and `RUSTUP_TOOLCHAIN` in the `[env]` configuration + table. This is considered to be not a use case Cargo would like to support, + since it will likely cause problems or lead to confusion. + [#12101](https://github.com/rust-lang/cargo/pull/12101) + [#12107](https://github.com/rust-lang/cargo/pull/12107) +- Better error message when getting an empty dependency table in Cargo.toml. + [#11997](https://github.com/rust-lang/cargo/pull/11997) +- Use restricted Damerau-Levenshtein algorithm to provide typo suggestions. + [#11963](https://github.com/rust-lang/cargo/pull/11963) + +### Fixed + +- Corrected the bug report URL for `cargo clippy --fix`. + [#11882](https://github.com/rust-lang/cargo/pull/11882) + +### Nightly only + +- The `-Zbuild-std` breakage of missing features in `nightly-2023-05-04` has + been fixed in `nightly-2023-05-05`. + [#12088](https://github.com/rust-lang/cargo/pull/12088) +- Recompile on profile rustflags changes. + [#11981](https://github.com/rust-lang/cargo/pull/11981) + +### Documentation + +### Internal + +- Cargo is now a Cargo workspace. We dogfood ourselves finally. + [#11851](https://github.com/rust-lang/cargo/pull/11851) + [#11994](https://github.com/rust-lang/cargo/pull/11994) + [#11996](https://github.com/rust-lang/cargo/pull/11996) +- Allow win/mac credential managers to build on all platforms. + [#11993](https://github.com/rust-lang/cargo/pull/11993) +- Use `openssl` only on non-Windows platforms. + [#11979](https://github.com/rust-lang/cargo/pull/11979) +- A new, straightforward issue labels system for Cargo contributors. + [docs](https://doc.crates.io/contrib/issues.html) + [#11995](https://github.com/rust-lang/cargo/pull/11995) + [#12002](https://github.com/rust-lang/cargo/pull/12002) + [#12003](https://github.com/rust-lang/cargo/pull/12003) + ## Cargo 1.70 (2023-06-01) -[9880b408...HEAD](https://github.com/rust-lang/cargo/compare/9880b408...HEAD) +[9880b408...rust-1.70.0](https://github.com/rust-lang/cargo/compare/9880b408...rust-1.70.0) ### Added +- 🎉 Added `cargo logout` command for removing an API token from the registry locally. + [docs](https://doc.rust-lang.org/nightly/cargo/commands/cargo-logout.html) + [#11919](https://github.com/rust-lang/cargo/pull/11919) + [#11950](https://github.com/rust-lang/cargo/pull/11950) +- Added `--ignore-rust-version` flag to `cargo install`. + [#11859](https://github.com/rust-lang/cargo/pull/11859) - The `CARGO_PKG_README` environment variable is now set to the path to the - README file when compiling a crate. + README file when compiling a crate. [#11645](https://github.com/rust-lang/cargo/pull/11645) - Cargo now displays richer information of Cargo target failed to compile. [#11636](https://github.com/rust-lang/cargo/pull/11636) @@ -18,6 +81,20 @@ ([docs](https://doc.rust-lang.org/nightly/cargo/reference/registries.html#registry-protocols)) [#11791](https://github.com/rust-lang/cargo/pull/11791) [#11783](https://github.com/rust-lang/cargo/pull/11783) +- ❗ `cargo login` and `cargo logout` now uses the registry specified in + `registry.default`. This was an unintentional regression. + [#11949](https://github.com/rust-lang/cargo/pull/11949) +- `cargo update` accurately shows `Downgrading` status when downgrading dependencies. + [#11839](https://github.com/rust-lang/cargo/pull/11839) +- Added more information to HTTP errors to help with debugging. + [#11878](https://github.com/rust-lang/cargo/pull/11878) +- Added delays to network retries in Cargo. + [#11881](https://github.com/rust-lang/cargo/pull/11881) +- Refined `cargo puslish` message when waiting for a publish complete. + [#11713](https://github.com/rust-lang/cargo/pull/11713) +- Better error message when `cargo install` from a git repository but found + multiple packages. + [#11835](https://github.com/rust-lang/cargo/pull/11835) ### Fixed @@ -29,6 +106,20 @@ [#11805](https://github.com/rust-lang/cargo/pull/11805) - Don't panic when [`patch`] involved in dependency resolution results in a conflict. [#11770](https://github.com/rust-lang/cargo/pull/11770) +- Fixed credential token format validation. + [#11951](https://github.com/rust-lang/cargo/pull/11951) +- Added the missing token format validation on publish. + [#11952](https://github.com/rust-lang/cargo/pull/11952) +- Fixed case mismatches when looking up env vars in the Config snapshot. + [#11824](https://github.com/rust-lang/cargo/pull/11824) +- `cargo new` generates the correct `.hgignore` aligning semantics with other + VCS ignore files. + [#11855](https://github.com/rust-lang/cargo/pull/11855) +- Stopped doing unnecessary fuzzy registry index queries. This significantly + reduces the amount of HTTP requests to remote registries for crates + containing `-` or `_` in their names. + [#11936](https://github.com/rust-lang/cargo/pull/11936) + [#11937](https://github.com/rust-lang/cargo/pull/11937) ### Nightly only @@ -42,6 +133,8 @@ ([docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html##gitoxide)) [#11448](https://github.com/rust-lang/cargo/pull/11448) [#11800](https://github.com/rust-lang/cargo/pull/11800) + [#11822](https://github.com/rust-lang/cargo/pull/11822) + [#11830](https://github.com/rust-lang/cargo/pull/11830) - Removed `-Zjobserver-per-rustc`. Its rustc counterpart never got landed. [#11764](https://github.com/rust-lang/cargo/pull/11764) @@ -51,16 +144,65 @@ [#11793](https://github.com/rust-lang/cargo/pull/11793) - Enhanced the documentation of timing report with graphs. [#11798](https://github.com/rust-lang/cargo/pull/11798) +- Clarified requirements about the state of the registry index after publish. + [#11926](https://github.com/rust-lang/cargo/pull/11926) +- Clarified docs on `-C` that it appears before the command. + [#11947](https://github.com/rust-lang/cargo/pull/11947) +- Clarified working directory behaviour for `cargo test`, `cargo bench` and + `cargo run`. + [#11901](https://github.com/rust-lang/cargo/pull/11901) +- Fixed the doc of `registries.name.index` configuration. + [#11880](https://github.com/rust-lang/cargo/pull/11880) +- Notice for potential unexpected shell expansions in help text of `cargo-add`. + [#11826](https://github.com/rust-lang/cargo/pull/11826) +- Updated external-tools JSON docs. + [#11918](https://github.com/rust-lang/cargo/pull/11918) +- Call out the differences between the index JSON and the API or metadata. + [#11927](https://github.com/rust-lang/cargo/pull/11927) +- Consistently use `@` when mentioning pkgid format. + [#11956](https://github.com/rust-lang/cargo/pull/11956) +- Enhanced Cargo Contributor Guide. + [#11825](https://github.com/rust-lang/cargo/pull/11825) + [#11842](https://github.com/rust-lang/cargo/pull/11842) + [#11869](https://github.com/rust-lang/cargo/pull/11869) + [#11876](https://github.com/rust-lang/cargo/pull/11876) +- Moved a part of Cargo Contributor Guide to Cargo API documentation. + [docs](https://doc.rust-lang.org/nightly/nightly-rustc/cargo) + [#11809](https://github.com/rust-lang/cargo/pull/11809) + [#11841](https://github.com/rust-lang/cargo/pull/11841) + [#11850](https://github.com/rust-lang/cargo/pull/11850) + [#11870](https://github.com/rust-lang/cargo/pull/11870) +- Cargo team now arranges + [office hours](https://github.com/rust-lang/cargo/wiki/Office-Hours)! + [#11903](https://github.com/rust-lang/cargo/pull/11903) ### Internal - Switched to `sha2` crate for SHA256 calculation. [#11795](https://github.com/rust-lang/cargo/pull/11795) [#11807](https://github.com/rust-lang/cargo/pull/11807) -- Updated to `base64` v0.21.0. +- Switched benchsuite to the index archive. + [#11933](https://github.com/rust-lang/cargo/pull/11933) +- Updated to `base64` 0.21.0. [#11796](https://github.com/rust-lang/cargo/pull/11796) +- Updated to `curl-sys` 0.4.61, which corresponds to curl 8.0.1. + [#11871](https://github.com/rust-lang/cargo/pull/11871) +- Updated to `proptest` 1.1.0. + [#11886](https://github.com/rust-lang/cargo/pull/11886) +- Updated to `git2` 0.17.0, which corresponds to libgit2 1.6.3. + [#11928](https://github.com/rust-lang/cargo/pull/11928) +- Updated to `clap` 4.2. + [#11904](https://github.com/rust-lang/cargo/pull/11904) - Integrated `cargo-deny` in Cargo its own CI pipeline. [#11761](https://github.com/rust-lang/cargo/pull/11761) +- Made non-blocking IO calls more robust. + [#11624](https://github.com/rust-lang/cargo/pull/11624) +- Dropped `derive` feature from `serde` in `cargo-platform`. + [#11915](https://github.com/rust-lang/cargo/pull/11915) +- Replaced `std::fs::canonicalize` with a more robust `try_canonicalize`. + [#11866](https://github.com/rust-lang/cargo/pull/11866) +- Enabled clippy warning on `disallowed_methods` for `std::env::var` and friends. + [#11828](https://github.com/rust-lang/cargo/pull/11828) ## Cargo 1.69 (2023-04-20) [985d561f...rust-1.69.0](https://github.com/rust-lang/cargo/compare/985d561f...rust-1.69.0) @@ -72,7 +214,7 @@ [#11558](https://github.com/rust-lang/cargo/pull/11558) - Cargo now suggests `cargo add` if you try to install a library crate. [#11410](https://github.com/rust-lang/cargo/pull/11410) -- Cargo now sets `CARGO_BIN_NAME` environment variable also for binary examples. +- Cargo now sets the `CARGO_BIN_NAME` environment variable also for binary examples. [#11705](https://github.com/rust-lang/cargo/pull/11705) ### Changed @@ -82,13 +224,12 @@ Cargo will enable default features of that dependency. [#11409](https://github.com/rust-lang/cargo/pull/11409) - ❗ Deny `CARGO_HOME` in `[env]` configuration table. Cargo itself doesn't - pick up this value, but recursive calls to cargo will. We consider it as a - wrong behavior to only pass it to recursive invocations. + pick up this value, but recursive calls to cargo would, which was not intended. [#11644](https://github.com/rust-lang/cargo/pull/11644) -- ❗ Debuginfo for build dependencies is now off if not explicit set. This is - expected to boost the overall build time. +- ❗ Debuginfo for build dependencies is now off if not explicitly set. This is + expected to improve the overall build time. [#11252](https://github.com/rust-lang/cargo/pull/11252) -- Cargo now emits errors on invalid alphanumeric token for crates.io. +- Cargo now emits errors on invalid alphanumeric characters in a registry token. [#11600](https://github.com/rust-lang/cargo/pull/11600) - `cargo add` now checks only the order of `[dependencies]` without considering `[dependencies.*]`. diff --git a/src/tools/cargo/Cargo.lock b/src/tools/cargo/Cargo.lock new file mode 100644 index 000000000..14fd1d056 --- /dev/null +++ b/src/tools/cargo/Cargo.lock @@ -0,0 +1,3755 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "342258dd14006105c2b75ab1bd7543a03bdf0cfc94383303ac212a04939dff6f" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-wincon", + "concolor-override", + "concolor-query", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23ea9e81bd02e310c216d080f6223c179012256e5151c41db88d12c88a1684d2" + +[[package]] +name = "anstyle-parse" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7d1bb534e9efed14f3e5f44e7dd1a4f709384023a4165199a4241e18dff0116" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-wincon" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3127af6145b149f3287bb9a0d10ad9c5692dba8c53ad48285e5bec4063834fa" +dependencies = [ + "anstyle", + "windows-sys 0.45.0", +] + +[[package]] +name = "anyhow" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" + +[[package]] +name = "arc-swap" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "benchsuite" +version = "0.0.0" +dependencies = [ + "cargo", + "criterion", + "flate2", + "tar", + "url", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24a6904aef64d73cf10ab17ebace7befb918b82164785cb89907993be7f83813" + +[[package]] +name = "bitmaps" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" +dependencies = [ + "typenum", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bstr" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09" +dependencies = [ + "memchr", + "once_cell", + "regex-automata", + "serde", +] + +[[package]] +name = "btoi" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd6407f73a9b8b6162d8a2ef999fe6afd7cc15902ebf42c5cd296addf17e0ad" +dependencies = [ + "num-traits", +] + +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "bytesize" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38fcc2979eff34a4b84e1cf9a1e3da42a7d44b3b690a40cdcb23e3d556cfb2e5" + +[[package]] +name = "camino" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2" +dependencies = [ + "serde", +] + +[[package]] +name = "capture" +version = "0.1.0" +dependencies = [ + "cargo_metadata", + "flate2", + "tar", + "toml", +] + +[[package]] +name = "cargo" +version = "0.72.1" +dependencies = [ + "anyhow", + "base64", + "bytesize", + "cargo-platform 0.1.3", + "cargo-test-macro", + "cargo-test-support", + "cargo-util", + "clap 4.2.1", + "crates-io", + "curl", + "curl-sys", + "env_logger 0.10.0", + "filetime", + "flate2", + "fwdansi", + "git2", + "git2-curl", + "gix", + "gix-features", + "glob", + "hex", + "hmac", + "home 0.5.5", + "http-auth", + "humantime 2.1.0", + "ignore", + "im-rc", + "indexmap", + "is-terminal", + "itertools", + "jobserver", + "lazy_static", + "lazycell", + "libc", + "libgit2-sys", + "log", + "memchr", + "opener", + "openssl", + "os_info", + "pasetors", + "pathdiff", + "pretty_env_logger", + "rand", + "rustfix", + "same-file", + "semver", + "serde", + "serde-value", + "serde_ignored", + "serde_json", + "sha1", + "shell-escape", + "snapbox", + "strip-ansi-escapes", + "tar", + "tempfile", + "termcolor", + "time", + "toml", + "toml_edit", + "unicode-width", + "unicode-xid", + "url", + "walkdir", + "windows-sys 0.48.0", +] + +[[package]] +name = "cargo-credential" +version = "0.2.0" + +[[package]] +name = "cargo-credential-1password" +version = "0.2.0" +dependencies = [ + "cargo-credential", + "serde", + "serde_json", +] + +[[package]] +name = "cargo-credential-gnome-secret" +version = "0.2.0" +dependencies = [ + "cargo-credential", + "pkg-config", +] + +[[package]] +name = "cargo-credential-macos-keychain" +version = "0.2.0" +dependencies = [ + "cargo-credential", + "security-framework", +] + +[[package]] +name = "cargo-credential-wincred" +version = "0.2.0" +dependencies = [ + "cargo-credential", + "windows-sys 0.48.0", +] + +[[package]] +name = "cargo-platform" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.3" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-test-macro" +version = "0.1.0" + +[[package]] +name = "cargo-test-support" +version = "0.1.0" +dependencies = [ + "anyhow", + "cargo-test-macro", + "cargo-util", + "crates-io", + "filetime", + "flate2", + "git2", + "glob", + "itertools", + "lazy_static", + "pasetors", + "serde", + "serde_json", + "snapbox", + "tar", + "termcolor", + "time", + "toml", + "url", + "windows-sys 0.48.0", +] + +[[package]] +name = "cargo-util" +version = "0.2.4" +dependencies = [ + "anyhow", + "core-foundation", + "filetime", + "hex", + "jobserver", + "libc", + "log", + "miow", + "same-file", + "sha2", + "shell-escape", + "tempfile", + "walkdir", + "windows-sys 0.48.0", +] + +[[package]] +name = "cargo_metadata" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +dependencies = [ + "camino", + "cargo-platform 0.1.2", + "semver", + "serde", + "serde_json", +] + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "bitflags 1.3.2", + "textwrap", + "unicode-width", +] + +[[package]] +name = "clap" +version = "4.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "223163f58c9a40c3b0a43e1c4b50a9ce09f007ea2cb1ec258a687945b4b7929f" +dependencies = [ + "anstream", + "anstyle", + "bitflags 1.3.2", + "clap_lex", + "strsim", + "terminal_size", +] + +[[package]] +name = "clap_lex" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" + +[[package]] +name = "clru" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8191fa7302e03607ff0e237d4246cc043ff5b3cb9409d995172ba3bea16b807" + +[[package]] +name = "concolor-override" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a855d4a1978dc52fb0536a04d384c2c0c1aa273597f08b77c8c4d3b2eec6037f" + +[[package]] +name = "concolor-query" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d11d52c3d7ca2e6d0040212be9e4dbbcd78b6447f535b6b561f449427944cf" +dependencies = [ + "windows-sys 0.45.0", +] + +[[package]] +name = "const-oid" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" + +[[package]] +name = "content_inspector" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7bda66e858c683005a53a9a60c69a4aca7eeaa45d124526e389f7aec8e62f38" +dependencies = [ + "memchr", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "cpufeatures" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" +dependencies = [ + "libc", +] + +[[package]] +name = "crates-io" +version = "0.37.0" +dependencies = [ + "anyhow", + "curl", + "percent-encoding", + "serde", + "serde_json", + "url", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "criterion" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" +dependencies = [ + "atty", + "cast", + "clap 2.34.0", + "criterion-plot", + "csv", + "itertools", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c2538c4e68e52548bacb3e83ac549f903d44f011ac9d5abb5e132e67d0808f7" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "csv" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b015497079b9a9d69c02ad25de6c0a6edef051ea6360a327d0bd05802ef64ad" +dependencies = [ + "csv-core", + "itoa 1.0.6", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + +[[package]] +name = "ct-codecs" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3b7eb4404b8195a9abb6356f4ac07d8ba267045c8d6d220ac4dc992e6cc75df" + +[[package]] +name = "ctor" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "curl" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22" +dependencies = [ + "curl-sys", + "libc", + "openssl-probe", + "openssl-sys", + "schannel", + "socket2", + "winapi", +] + +[[package]] +name = "curl-sys" +version = "0.4.61+curl-8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14d05c10f541ae6f3bc5b3d923c20001f47db7d5f0b2bc6ad16490133842db79" +dependencies = [ + "cc", + "libc", + "libnghttp2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", + "winapi", +] + +[[package]] +name = "der" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b10af9f9f9f2134a42d3f8aa74658660f2e0234b0eb81bd171df8aa32779ed" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dunce" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bd4b30a6560bbd9b4620f4de34c3f14f60848e58a9b7216801afcb4c7b31c3c" + +[[package]] +name = "ecdsa" +version = "0.16.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a48e5d537b8a30c0b023116d981b16334be1485af7ca68db3a2b7024cbc957fd" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", +] + +[[package]] +name = "ed25519-compact" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a3d382e8464107391c8706b4c14b087808ecb909f6c15c34114bc42e53a9e4c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "elliptic-curve" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75c71eaa367f2e5d556414a8eea812bc62985c879748d6403edabd9cb03f16e7" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime 1.3.0", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime 2.1.0", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" + +[[package]] +name = "filetime" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.2.16", + "windows-sys 0.48.0", +] + +[[package]] +name = "flate2" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +dependencies = [ + "crc32fast", + "libz-sys", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fwdansi" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c1f5787fe85505d1f7777268db5103d80a7a374d2316a7ce262e57baf8f208" +dependencies = [ + "memchr", + "termcolor", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "git2" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b7905cdfe33d31a88bb2e8419ddd054451f5432d1da9eaf2ac7804ee1ea12d5" +dependencies = [ + "bitflags 1.3.2", + "libc", + "libgit2-sys", + "log", + "openssl-probe", + "openssl-sys", + "url", +] + +[[package]] +name = "git2-curl" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8f8b7432b72928cff76f69e59ed5327f94a52763731e71274960dee72fe5f8c" +dependencies = [ + "curl", + "git2", + "log", + "url", +] + +[[package]] +name = "gix" +version = "0.44.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bf41b61f7df395284f7a579c0fa1a7e012c5aede655174d4e91299ef1cac643" +dependencies = [ + "gix-actor", + "gix-attributes", + "gix-config", + "gix-credentials", + "gix-date", + "gix-diff", + "gix-discover", + "gix-features", + "gix-fs", + "gix-glob", + "gix-hash", + "gix-hashtable", + "gix-ignore", + "gix-index", + "gix-lock", + "gix-mailmap", + "gix-object", + "gix-odb", + "gix-pack", + "gix-path", + "gix-prompt", + "gix-protocol", + "gix-ref", + "gix-refspec", + "gix-revision", + "gix-sec", + "gix-tempfile", + "gix-transport", + "gix-traverse", + "gix-url", + "gix-utils", + "gix-validate", + "gix-worktree", + "log", + "once_cell", + "prodash", + "signal-hook", + "smallvec", + "thiserror", + "unicode-normalization", +] + +[[package]] +name = "gix-actor" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "848efa0f1210cea8638f95691c82a46f98a74b9e3524f01d4955ebc25a8f84f3" +dependencies = [ + "bstr", + "btoi", + "gix-date", + "itoa 1.0.6", + "nom", + "thiserror", +] + +[[package]] +name = "gix-attributes" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3015baa01ad2122fbcaab7863c857a603eb7b7ec12ac8141207c42c6439805e2" +dependencies = [ + "bstr", + "gix-glob", + "gix-path", + "gix-quote", + "kstring", + "log", + "smallvec", + "thiserror", + "unicode-bom", +] + +[[package]] +name = "gix-bitmap" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55a95f4942360766c3880bdb2b4b57f1ef73b190fc424755e7fdf480430af618" +dependencies = [ + "thiserror", +] + +[[package]] +name = "gix-chunk" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0d39583cab06464b8bf73b3f1707458270f0e7383cb24c3c9c1a16e6f792978" +dependencies = [ + "thiserror", +] + +[[package]] +name = "gix-command" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2c6f75c1e0f924de39e750880a6e21307194bb1ab773efe3c7d2d787277f8ab" +dependencies = [ + "bstr", +] + +[[package]] +name = "gix-config" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d252a0eddb6df74600d3d8872dc9fe98835a7da43110411d705b682f49d4ac1" +dependencies = [ + "bstr", + "gix-config-value", + "gix-features", + "gix-glob", + "gix-path", + "gix-ref", + "gix-sec", + "log", + "memchr", + "nom", + "once_cell", + "smallvec", + "thiserror", + "unicode-bom", +] + +[[package]] +name = "gix-config-value" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786861e84a5793ad5f863d846de5eb064cd23b87e61ad708c8c402608202e7be" +dependencies = [ + "bitflags 2.2.1", + "bstr", + "gix-path", + "libc", + "thiserror", +] + +[[package]] +name = "gix-credentials" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4874a4fc11ffa844a3c2b87a66957bda30a73b577ef1acf15ac34df5745de5ff" +dependencies = [ + "bstr", + "gix-command", + "gix-config-value", + "gix-path", + "gix-prompt", + "gix-sec", + "gix-url", + "thiserror", +] + +[[package]] +name = "gix-date" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99056f37270715f5c7584fd8b46899a2296af9cae92463bf58b8bd1f5a78e553" +dependencies = [ + "bstr", + "itoa 1.0.6", + "thiserror", + "time", +] + +[[package]] +name = "gix-diff" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644a0f2768bc42d7a69289ada80c9e15c589caefc6a315d2307202df83ed1186" +dependencies = [ + "gix-hash", + "gix-object", + "imara-diff", + "thiserror", +] + +[[package]] +name = "gix-discover" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5012710ebdecf6193c6866d6409a3b702a4aa0d78c605bc343590b44ab9962a1" +dependencies = [ + "bstr", + "dunce", + "gix-hash", + "gix-path", + "gix-ref", + "gix-sec", + "thiserror", +] + +[[package]] +name = "gix-features" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf69b0f5c701cc3ae22d3204b671907668f6437ca88862d355eaf9bc47a4f897" +dependencies = [ + "bytes", + "crc32fast", + "crossbeam-channel", + "flate2", + "gix-hash", + "libc", + "once_cell", + "parking_lot", + "prodash", + "sha1_smol", + "thiserror", + "walkdir", +] + +[[package]] +name = "gix-fs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b37a1832f691fdc09910bd267f9a2e413737c1f9ec68c6e31f9e802616278a9" +dependencies = [ + "gix-features", +] + +[[package]] +name = "gix-glob" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07c98204529ac3f24b34754540a852593d2a4c7349008df389240266627a72a" +dependencies = [ + "bitflags 2.2.1", + "bstr", + "gix-features", + "gix-path", +] + +[[package]] +name = "gix-hash" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078eec3ac2808cc03f0bddd2704cb661da5c5dc33b41a9d7947b141d499c7c42" +dependencies = [ + "hex", + "thiserror", +] + +[[package]] +name = "gix-hashtable" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afebb85691c6a085b114e01a27f4a61364519298c5826cb87a45c304802299bc" +dependencies = [ + "gix-hash", + "hashbrown 0.13.2", + "parking_lot", +] + +[[package]] +name = "gix-ignore" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba205b6df563e2906768bb22834c82eb46c5fdfcd86ba2c347270bc8309a05b2" +dependencies = [ + "bstr", + "gix-glob", + "gix-path", + "unicode-bom", +] + +[[package]] +name = "gix-index" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa282756760f79c401d4f4f42588fbb4aa27bbb4b0830f3b4d3480c21a4ac5a7" +dependencies = [ + "bitflags 2.2.1", + "bstr", + "btoi", + "filetime", + "gix-bitmap", + "gix-features", + "gix-hash", + "gix-lock", + "gix-object", + "gix-traverse", + "itoa 1.0.6", + "memmap2", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-lock" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b80172055c5d8017a48ddac5cc7a95421c00211047db0165c97853c4f05194" +dependencies = [ + "fastrand", + "gix-tempfile", + "thiserror", +] + +[[package]] +name = "gix-mailmap" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8856cec3bdc3610c06970d28b6cb20a0c6621621cf9a8ec48cbd23f2630f362" +dependencies = [ + "bstr", + "gix-actor", + "thiserror", +] + +[[package]] +name = "gix-object" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9bb30ce0818d37096daa29efe361a4bc6dd0b51a5726598898be7e9a40a01e1" +dependencies = [ + "bstr", + "btoi", + "gix-actor", + "gix-features", + "gix-hash", + "gix-validate", + "hex", + "itoa 1.0.6", + "nom", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-odb" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca2f324aa67672b6d0f2c0fa93f96eb6a7029d260e4c1df5dce3c015f5e5add" +dependencies = [ + "arc-swap", + "gix-features", + "gix-hash", + "gix-object", + "gix-pack", + "gix-path", + "gix-quote", + "parking_lot", + "tempfile", + "thiserror", +] + +[[package]] +name = "gix-pack" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "164a515900a83257ae4aa80e741655bee7a2e39113fb535d7a5ac623b445ff20" +dependencies = [ + "clru", + "gix-chunk", + "gix-diff", + "gix-features", + "gix-hash", + "gix-hashtable", + "gix-object", + "gix-path", + "gix-tempfile", + "gix-traverse", + "memmap2", + "parking_lot", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-packetline" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51f53abaf1171d2fe99f80ac8ed6645904a1bfd706674749ac112bdd2d4f0777" +dependencies = [ + "bstr", + "hex", + "thiserror", +] + +[[package]] +name = "gix-path" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fc78f47095a0c15aea0e66103838f0748f4494bf7a9555dfe0f00425400396c" +dependencies = [ + "bstr", + "home 0.5.5", + "once_cell", + "thiserror", +] + +[[package]] +name = "gix-prompt" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330d11fdf88fff3366c2491efde2f3e454958efe7d5ddf60272e8fb1d944bb01" +dependencies = [ + "gix-command", + "gix-config-value", + "parking_lot", + "rustix", + "thiserror", +] + +[[package]] +name = "gix-protocol" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877e49417f1730f4dbc2f7d9a2ab0f8b2f49ef08f97270691403ecde3d961e3a" +dependencies = [ + "bstr", + "btoi", + "gix-credentials", + "gix-features", + "gix-hash", + "gix-transport", + "maybe-async", + "nom", + "thiserror", +] + +[[package]] +name = "gix-quote" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a282f5a8d9ee0b09ec47390ac727350c48f2f5c76d803cd8da6b3e7ad56e0bcb" +dependencies = [ + "bstr", + "btoi", + "thiserror", +] + +[[package]] +name = "gix-ref" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8212ecfe41815a2f1b059d82171d6276758cfac5506a5e0f04ad45ef0b1924a" +dependencies = [ + "gix-actor", + "gix-features", + "gix-fs", + "gix-hash", + "gix-lock", + "gix-object", + "gix-path", + "gix-tempfile", + "gix-validate", + "memmap2", + "nom", + "thiserror", +] + +[[package]] +name = "gix-refspec" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6ea733820df67e4cd7797deb12727905824d8f5b7c59d943c456d314475892" +dependencies = [ + "bstr", + "gix-hash", + "gix-revision", + "gix-validate", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-revision" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "810f35e9afeccca999d5d348b239f9c162353127d2e13ff3240e31b919e35476" +dependencies = [ + "bstr", + "gix-date", + "gix-hash", + "gix-hashtable", + "gix-object", + "thiserror", +] + +[[package]] +name = "gix-sec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "794520043d5a024dfeac335c6e520cb616f6963e30dab995892382e998c12897" +dependencies = [ + "bitflags 2.2.1", + "gix-path", + "libc", + "windows", +] + +[[package]] +name = "gix-tempfile" +version = "5.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2ceb30a610e3f5f2d5f9a5114689fde507ba9417705a8cf3429604275b2153c" +dependencies = [ + "libc", + "once_cell", + "parking_lot", + "signal-hook", + "signal-hook-registry", + "tempfile", +] + +[[package]] +name = "gix-transport" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f01c2bf7b989c679695ef635fc7d9e80072e08101be4b53193c8e8b649900102" +dependencies = [ + "base64", + "bstr", + "curl", + "gix-command", + "gix-credentials", + "gix-features", + "gix-packetline", + "gix-quote", + "gix-sec", + "gix-url", + "thiserror", +] + +[[package]] +name = "gix-traverse" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5be1e807f288c33bb005075111886cceb43ed8a167b3182a0f62c186e2a0dd1" +dependencies = [ + "gix-hash", + "gix-hashtable", + "gix-object", + "thiserror", +] + +[[package]] +name = "gix-url" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc77f89054297cc81491e31f1bab4027e554b5ef742a44bd7035db9a0f78b76" +dependencies = [ + "bstr", + "gix-features", + "gix-path", + "home 0.5.5", + "thiserror", + "url", +] + +[[package]] +name = "gix-utils" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c10b69beac219acb8df673187a1f07dde2d74092f974fb3f9eb385aeb667c909" +dependencies = [ + "fastrand", +] + +[[package]] +name = "gix-validate" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd629d3680773e1785e585d76fd4295b740b559cad9141517300d99a0c8c049" +dependencies = [ + "bstr", + "thiserror", +] + +[[package]] +name = "gix-worktree" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10bf56a1f5037d84293ea6cece61d9f27c4866b1e13c1c95f37cf56b7da7af25" +dependencies = [ + "bstr", + "filetime", + "gix-attributes", + "gix-features", + "gix-fs", + "gix-glob", + "gix-hash", + "gix-ignore", + "gix-index", + "gix-object", + "gix-path", + "io-close", + "thiserror", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "globset" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" +dependencies = [ + "aho-corasick", + "bstr", + "fnv", + "log", + "regex", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "handlebars" +version = "3.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4498fc115fa7d34de968184e473529abb40eeb6be8bc5f7faba3d08c316cb3e3" +dependencies = [ + "log", + "pest", + "pest_derive", + "quick-error 2.0.1", + "serde", + "serde_json", + "walkdir", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "home" +version = "0.5.6" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "http-auth" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5430cacd7a1f9a02fbeb350dfc81a0e5ed42d81f3398cb0ba184017f85bdcfbc" +dependencies = [ + "memchr", +] + +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error 1.2.3", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "ignore" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" +dependencies = [ + "globset", + "lazy_static", + "log", + "memchr", + "regex", + "same-file", + "thread_local", + "walkdir", + "winapi-util", +] + +[[package]] +name = "im-rc" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1955a75fa080c677d3972822ec4bad316169ab1cfc6c257a942c2265dbe5fe" +dependencies = [ + "bitmaps", + "rand_core", + "rand_xoshiro", + "sized-chunks", + "typenum", + "version_check", +] + +[[package]] +name = "imara-diff" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e98c1d0ad70fc91b8b9654b1f33db55e59579d3b3de2bffdced0fdb810570cb8" +dependencies = [ + "ahash", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-close" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cadcf447f06744f8ce713d2d6239bb5bde2c357a452397a9ed90c625da390bc" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "jobserver" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "kstring" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3066350882a1cd6d950d055997f379ac37fd39f81cd4d8ed186032eb3c5747" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + +[[package]] +name = "libc" +version = "0.2.144" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" + +[[package]] +name = "libgit2-sys" +version = "0.15.1+1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4577bde8cdfc7d6a2a4bcb7b049598597de33ffd337276e9c7db6cd4a2cee7" +dependencies = [ + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] + +[[package]] +name = "libm" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" + +[[package]] +name = "libnghttp2-sys" +version = "0.1.7+1.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ed28aba195b38d5ff02b9170cbff627e336a20925e43b4945390401c5dc93f" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "libssh2-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eb31c1778188ae1e64398743890d0877fef36d11521ac60406b42016e8c2cf" + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "maybe-async" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f1b8c13cb1f814b634a96b2c725449fe7ed464a7b8781de8688be5ffbd3f305" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "mdman" +version = "0.0.0" +dependencies = [ + "anyhow", + "handlebars", + "pretty_assertions", + "pulldown-cmark", + "same-file", + "serde_json", + "url", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + +[[package]] +name = "miow" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ffbca2f655e33c08be35d87278e5b18b89550a37dbd598c20db92f6a471123" +dependencies = [ + "windows-sys 0.42.0", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi 0.2.6", + "libc", +] + +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "opener" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "293c15678e37254c15bd2f092314abb4e51d7fdde05c2021279c12631b54f005" +dependencies = [ + "bstr", + "winapi", +] + +[[package]] +name = "openssl" +version = "0.10.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e30d8bc91859781f0a943411186324d580f2bbeb71b452fe91ae344806af3f1" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.14", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-src" +version = "111.25.3+1.1.1t" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924757a6a226bf60da5f7dd0311a34d2b52283dd82ddeb103208ddc66362f80c" +dependencies = [ + "cc", +] + +[[package]] +name = "openssl-sys" +version = "0.9.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d3d193fb1488ad46ffe3aaabc912cc931d02ee8518fe2959aea8ef52718b0c0" +dependencies = [ + "cc", + "libc", + "openssl-src", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "ordered-float" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" +dependencies = [ + "num-traits", +] + +[[package]] +name = "orion" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbe74a766292f94f7e69db5a7bf010eadd944f24186c463fe578a7e637582066" +dependencies = [ + "fiat-crypto", + "subtle", + "zeroize", +] + +[[package]] +name = "os_info" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "006e42d5b888366f1880eda20371fedde764ed2213dc8496f49622fa0c99cd5e" +dependencies = [ + "log", + "serde", + "winapi", +] + +[[package]] +name = "output_vt100" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" +dependencies = [ + "winapi", +] + +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "windows-sys 0.45.0", +] + +[[package]] +name = "partial_ref" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f728bc9b1479656e40cba507034904a8c44027c0efdbbaf6a4bdc5f2d3a910c" +dependencies = [ + "partial_ref_derive", +] + +[[package]] +name = "partial_ref_derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e1d2cb5b898b5a5342e994e0d0c367dbfe69cbf717cd307045ec9fb057581" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "pasetors" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824bf633b85dc1dece2eb07161627ba5d90a951597cd5dbf8d85f4d82b7aea69" +dependencies = [ + "ct-codecs", + "ed25519-compact", + "getrandom", + "orion", + "p384", + "rand_core", + "regex", + "serde", + "serde_json", + "sha2", + "subtle", + "time", + "zeroize", +] + +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "pest" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1403e8401ad5dedea73c626b99758535b342502f8d1e361f4a2dd952749122" +dependencies = [ + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be99c4c1d2fc2769b1d00239431d711d08f6efedcecb8b6e30707160aee99c15" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e56094789873daa36164de2e822b3888c6ae4b4f9da555a1103587658c805b1e" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.14", +] + +[[package]] +name = "pest_meta" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6733073c7cff3d8459fda0e42f13a047870242aed8b509fe98000928975f359e" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + +[[package]] +name = "plotters" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" + +[[package]] +name = "plotters-svg" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "pretty_assertions" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" +dependencies = [ + "ctor", + "diff", + "output_vt100", + "yansi", +] + +[[package]] +name = "pretty_env_logger" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" +dependencies = [ + "env_logger 0.7.1", + "log", +] + +[[package]] +name = "primeorder" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8d3875361e28f7753baefef104386e7aa47642c93023356d97fdef4003bfb5" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "proc-macro2" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prodash" +version = "23.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9516b775656bc3e8985e19cd4b8c0c0de045095074e453d2c0a513b5f978392d" +dependencies = [ + "parking_lot", +] + +[[package]] +name = "proptest" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29f1b898011ce9595050a68e60f90bad083ff2987a695a42357134c8381fba70" +dependencies = [ + "bit-set", + "bitflags 1.3.2", + "byteorder", + "lazy_static", + "num-traits", + "quick-error 2.0.1", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "pulldown-cmark" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63" +dependencies = [ + "bitflags 1.3.2", + "memchr", + "unicase", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quote" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "resolver-tests" +version = "0.0.0" +dependencies = [ + "cargo", + "cargo-util", + "is-terminal", + "lazy_static", + "proptest", + "varisat", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustfix" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd2853d9e26988467753bd9912c3a126f642d05d229a4b53f5752ee36c56481" +dependencies = [ + "anyhow", + "log", + "serde", + "serde_json", +] + +[[package]] +name = "rustix" +version = "0.37.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0661814f891c57c930a610266415528da53c4933e6dea5fb350cbfe048a9ece" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error 1.2.3", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +dependencies = [ + "windows-sys 0.42.0", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "sec1" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0aec48e813d6b90b15f0b8948af3c63483992dee44c03e9930b3eebdabe046e" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +dependencies = [ + "serde", +] + +[[package]] +name = "semver-check" +version = "0.0.0" +dependencies = [ + "tempfile", +] + +[[package]] +name = "serde" +version = "1.0.160" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.160" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.14", +] + +[[package]] +name = "serde_ignored" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94eb4a4087ba8bdf14a9208ac44fddbf55c01a6195f7edfc511ddaff6cae45a6" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_json" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" +dependencies = [ + "itoa 1.0.6", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +dependencies = [ + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shell-escape" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" + +[[package]] +name = "signal-hook" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "similar" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" + +[[package]] +name = "sized-chunks" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +dependencies = [ + "bitmaps", + "typenum", +] + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "snapbox" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9615402f9cff539301119bdf2c2f328739cf2b45c2116666618fb6ac399f75bb" +dependencies = [ + "anstream", + "anstyle", + "content_inspector", + "dunce", + "filetime", + "normalize-line-endings", + "similar", + "snapbox-macros", + "tempfile", + "walkdir", +] + +[[package]] +name = "snapbox-macros" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8e40c667388ed1cb5060f545d0013bf0a23efdfa6c5c3e9ef592de391cd860f" +dependencies = [ + "anstream", +] + +[[package]] +name = "socket2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "spki" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a5be806ab6f127c3da44b7378837ebf01dadca8510a0e572460216b228bd0e" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strip-ansi-escapes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "011cbb39cf7c1f62871aea3cc46e5817b0937b49e9447370c93cacbe93a766d8" +dependencies = [ + "vte", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", +] + +[[package]] +name = "tar" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec96d2ffad078296368d46ff1cb309be1c23c513b4ab0e22a45de0185275ac96" +dependencies = [ + "filetime", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.3.5", + "rustix", + "windows-sys 0.45.0", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "terminal_size" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" +dependencies = [ + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.14", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" +dependencies = [ + "itoa 1.0.6", + "libc", + "num_threads", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" +dependencies = [ + "time-core", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "ucd-trie" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-bom" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98e90c70c9f0d4d1ee6d0a7d04aa06cb9bbd53d8cfbdd62a0269a7c2eb640552" + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "varisat" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe609851d1e9196674ac295f656bd8601200a1077343d22b345013497807caf" +dependencies = [ + "anyhow", + "itoa 0.4.8", + "leb128", + "log", + "ordered-float", + "partial_ref", + "rustc-hash", + "serde", + "thiserror", + "varisat-checker", + "varisat-dimacs", + "varisat-formula", + "varisat-internal-macros", + "varisat-internal-proof", + "vec_mut_scan", +] + +[[package]] +name = "varisat-checker" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135c977c5913ed6e98f6b81b8e4d322211303b7d40dae773caef7ad1de6c763b" +dependencies = [ + "anyhow", + "log", + "partial_ref", + "rustc-hash", + "smallvec", + "thiserror", + "varisat-dimacs", + "varisat-formula", + "varisat-internal-proof", +] + +[[package]] +name = "varisat-dimacs" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1dee4e21be1f04c0a939f7ae710cced47233a578de08a1b3c7d50848402636" +dependencies = [ + "anyhow", + "itoa 0.4.8", + "thiserror", + "varisat-formula", +] + +[[package]] +name = "varisat-formula" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395c5543b9bfd9076d6d3af49d6c34a4b91b0b355998c0a5ec6ed7265d364520" + +[[package]] +name = "varisat-internal-macros" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "602ece773543d066aa7848455486c6c0422a3f214da7a2b899100f3c4f12408d" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", + "synstructure", +] + +[[package]] +name = "varisat-internal-proof" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6163bb7bc9018af077b76d64f976803d141c36a27d640f1437dddc4fd527d207" +dependencies = [ + "anyhow", + "varisat-formula", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vec_mut_scan" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ed610a8d5e63d9c0e31300e8fdb55104c5f21e422743a9dc74848fa8317fd2" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "vte" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983" +dependencies = [ + "arrayvec", + "utf8parse", + "vte_generate_state_changes", +] + +[[package]] +name = "vte_generate_state_changes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + +[[package]] +name = "walkdir" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 1.0.109", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" + +[[package]] +name = "web-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "winnow" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" +dependencies = [ + "memchr", +] + +[[package]] +name = "xtask-build-man" +version = "0.0.0" + +[[package]] +name = "xtask-stale-label" +version = "0.0.0" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "xtask-unpublished" +version = "0.0.0" +dependencies = [ + "anyhow", + "cargo", + "clap 4.2.1", + "env_logger 0.10.0", + "log", +] + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/src/tools/cargo/Cargo.toml b/src/tools/cargo/Cargo.toml index 56c9827cb..05c95c727 100644 --- a/src/tools/cargo/Cargo.toml +++ b/src/tools/cargo/Cargo.toml @@ -1,41 +1,45 @@ -[package] -name = "cargo" -version = "0.71.0" -edition = "2021" -license = "MIT OR Apache-2.0" -homepage = "https://crates.io" -repository = "https://github.com/rust-lang/cargo" -documentation = "https://docs.rs/cargo" -readme = "README.md" -description = """ -Cargo, a package manager for Rust. -""" - -[lib] -name = "cargo" -path = "src/cargo/lib.rs" +[workspace] +resolver = "2" +members = [ + "crates/*", + "credential/*", + "benches/benchsuite", + "benches/capture", +] +exclude = [ + "target/", # exclude bench testing +] -[dependencies] +[workspace.dependencies] anyhow = "1.0.47" base64 = "0.21.0" bytesize = "1.0" -cargo-platform = { path = "crates/cargo-platform", version = "0.1.2" } -cargo-util = { path = "crates/cargo-util", version = "0.2.4" } +cargo = { path = "" } +cargo-credential = { version = "0.2.0", path = "credential/cargo-credential" } +cargo-platform = { path = "crates/cargo-platform", version = "0.1.3" } +cargo-test-macro = { path = "crates/cargo-test-macro" } +cargo-test-support = { path = "crates/cargo-test-support" } +cargo-util = { version = "0.2.4", path = "crates/cargo-util" } +cargo_metadata = "0.14.0" clap = "4.2.0" -crates-io = { path = "crates/crates-io", version = "0.36.0" } -curl = { version = "0.4.44", features = ["http2"] } +core-foundation = { version = "0.9.0", features = ["mac_os_10_7_support"] } +crates-io = { version = "0.37.0", path = "crates/crates-io" } +criterion = { version = "0.3.5", features = ["html_reports"] } +curl = "0.4.44" curl-sys = "0.4.61" env_logger = "0.10.0" filetime = "0.2.9" flate2 = { version = "1.0.3", default-features = false, features = ["zlib"] } -git2 = "0.17.0" +fwdansi = "1.1.0" +git2 = "0.17.1" git2-curl = "0.18.0" -gix = { version = "0.39.0", default-features = false, features = ["blocking-http-transport-curl", "progress-tree"] } -gix-features-for-configuration-only = { version = "0.28.0", package = "gix-features", features = [ "parallel" ] } +gix = { version = "0.44.1", default-features = false, features = ["blocking-http-transport-curl", "progress-tree"] } +gix-features-for-configuration-only = { version = "0.29.0", package = "gix-features", features = [ "parallel" ] } glob = "0.3.0" -hex = "0.4" +handlebars = { version = "3.2.1", features = ["dir_source"] } +hex = "0.4.2" hmac = "0.12.1" -home = "0.5" +home = "0.5.5" http-auth = { version = "0.1.6", default-features = false } humantime = "2.0.0" ignore = "0.4.7" @@ -44,49 +48,137 @@ indexmap = "1" is-terminal = "0.4.4" itertools = "0.10.0" jobserver = "0.1.26" -lazy_static = "1.2.0" +lazy_static = "1.3.0" lazycell = "1.2.0" -libc = "0.2" -libgit2-sys = "0.15.0" -log = "0.4.6" +libc = "0.2.144" +libgit2-sys = "0.15.1" +log = "0.4.17" memchr = "2.1.3" +miow = "0.5.0" opener = "0.5" -openssl = { version = '0.10.11', optional = true } +openssl ="0.10.50" os_info = "3.5.0" pasetors = { version = "0.6.4", features = ["v3", "paserk", "std", "serde"] } pathdiff = "0.2" -pretty_env_logger = { version = "0.4", optional = true } +percent-encoding = "2.0" +pkg-config = "0.3.19" +pretty_assertions = "1.3.0" +pretty_env_logger = "0.4" +proptest = "1.1.0" +pulldown-cmark = { version = "0.9.2", default-features = false } rand = "0.8.5" rustfix = "0.6.0" +same-file = "1.0.6" +security-framework = "2.0.0" semver = { version = "1.0.3", features = ["serde"] } -serde = { version = "1.0.123", features = ["derive"] } +serde = "1.0.123" serde-value = "0.7.0" serde_ignored = "0.1.0" -serde_json = { version = "1.0.30", features = ["raw_value"] } +serde_json = "1.0.59" sha1 = "0.10.5" +sha2 = "0.10.6" shell-escape = "0.1.4" +snapbox = { version = "0.4.0", features = ["diff", "path"] } strip-ansi-escapes = "0.1.0" -tar = { version = "0.4.38", default-features = false } -tempfile = "3.0" -termcolor = "1.1" -time = { version = "0.3", features = ["parsing", "formatting"]} +tar = { version = "0.4.39", default-features = false } +tempfile = "3.1.0" +termcolor = "1.1.2" +time = { version = "0.3", features = ["parsing", "formatting"] } toml = "0.7.0" toml_edit = "0.19.0" unicode-width = "0.1.5" unicode-xid = "0.2.0" url = "2.2.2" -walkdir = "2.2" +varisat = "0.2.1" +walkdir = "2.3.1" +windows-sys = "0.48" -# 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" +[package] +name = "cargo" +version = "0.72.1" +edition = "2021" +license = "MIT OR Apache-2.0" +homepage = "https://crates.io" +repository = "https://github.com/rust-lang/cargo" +documentation = "https://docs.rs/cargo" +readme = "README.md" +description = """ +Cargo, a package manager for Rust. +""" + +[lib] +name = "cargo" +path = "src/cargo/lib.rs" + +[dependencies] +anyhow.workspace = true +base64.workspace = true +bytesize.workspace = true +cargo-platform.workspace = true +cargo-util.workspace = true +clap = { workspace = true, features = ["wrap_help"] } +crates-io.workspace = true +curl = { workspace = true, features = ["http2"] } +curl-sys.workspace = true +env_logger.workspace = true +filetime.workspace = true +flate2.workspace = true +git2.workspace = true +git2-curl.workspace = true +gix.workspace = true +gix-features-for-configuration-only.workspace = true +glob.workspace = true +hex.workspace = true +hmac.workspace = true +home.workspace = true +http-auth.workspace = true +humantime.workspace = true +ignore.workspace = true +im-rc.workspace = true +indexmap.workspace = true +is-terminal.workspace = true +itertools.workspace = true +jobserver.workspace = true +lazy_static.workspace = true +lazycell.workspace = true +libc.workspace = true +libgit2-sys.workspace = true +log.workspace = true +memchr.workspace = true +opener.workspace = true +os_info.workspace = true +pasetors.workspace = true +pathdiff.workspace = true +pretty_env_logger = { workspace = true, optional = true } +rand.workspace = true +rustfix.workspace = true +semver.workspace = true +serde = { workspace = true, features = ["derive"] } +serde-value.workspace = true +serde_ignored.workspace = true +serde_json = { workspace = true, features = ["raw_value"] } +sha1.workspace = true +shell-escape.workspace = true +strip-ansi-escapes.workspace = true +tar.workspace = true +tempfile.workspace = true +termcolor.workspace = true +time.workspace = true +toml.workspace = true +toml_edit.workspace = true +unicode-width.workspace = true +unicode-xid.workspace = true +url.workspace = true +walkdir.workspace = true + +[target.'cfg(not(windows))'.dependencies] +openssl = { workspace = true, optional = true } [target.'cfg(windows)'.dependencies] -fwdansi = "1.1.0" +fwdansi.workspace = true [target.'cfg(windows)'.dependencies.windows-sys] -version = "0.45" +workspace = true features = [ "Win32_Foundation", "Win32_Storage_FileSystem", @@ -99,14 +191,14 @@ features = [ ] [dev-dependencies] -cargo-test-macro = { path = "crates/cargo-test-macro" } -cargo-test-support = { path = "crates/cargo-test-support" } -same-file = "1.0.6" -snapbox = { version = "0.4.0", features = ["diff", "path"] } +cargo-test-macro.workspace = true +cargo-test-support.workspace = true +same-file.workspace = true +snapbox.workspace = true [build-dependencies] -flate2 = { version = "1.0.3", default-features = false, features = ["zlib"] } -tar = { version = "0.4.38", default-features = false } +flate2.workspace = true +tar.workspace = true [[bin]] name = "cargo" @@ -117,3 +209,5 @@ doc = false vendored-openssl = ["openssl/vendored"] vendored-libgit2 = ["libgit2-sys/vendored"] pretty-env-logger = ["pretty_env_logger"] +# This is primarily used by rust-lang/rust distributing cargo the executable. +all-static = ['vendored-openssl', 'curl/static-curl', 'curl/force-system-lib-on-osx'] diff --git a/src/tools/cargo/benches/benchsuite/Cargo.toml b/src/tools/cargo/benches/benchsuite/Cargo.toml index f4bc3583a..782e6c101 100644 --- a/src/tools/cargo/benches/benchsuite/Cargo.toml +++ b/src/tools/cargo/benches/benchsuite/Cargo.toml @@ -1,20 +1,19 @@ [package] name = "benchsuite" -version = "0.1.0" +version = "0.0.0" edition = "2021" license = "MIT OR Apache-2.0" homepage = "https://github.com/rust-lang/cargo" repository = "https://github.com/rust-lang/cargo" -documentation = "https://docs.rs/cargo-platform" description = "Benchmarking suite for Cargo." +publish = false [dependencies] -cargo = { path = "../.." } -# Consider removing html_reports in 0.4 and switching to `cargo criterion`. -criterion = { version = "0.3.5", features = ["html_reports"] } -flate2 = { version = "1.0.3", default-features = false, features = ["zlib"] } -tar = { version = "0.4.38", default-features = false } -url = "2.2.2" +cargo.workspace = true +criterion.workspace = true +flate2.workspace = true +tar.workspace = true +url.workspace = true [lib] bench = false diff --git a/src/tools/cargo/benches/capture/Cargo.toml b/src/tools/cargo/benches/capture/Cargo.toml index 25a901777..6319a0130 100644 --- a/src/tools/cargo/benches/capture/Cargo.toml +++ b/src/tools/cargo/benches/capture/Cargo.toml @@ -4,9 +4,10 @@ version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" description = "Tool for capturing a real-world workspace for benchmarking." +publish = false [dependencies] -cargo_metadata = "0.14.0" -flate2 = { version = "1.0.3", default-features = false, features = ["zlib"] } -tar = { version = "0.4.38", default-features = false } -toml = "0.7.0" +cargo_metadata.workspace = true +flate2.workspace = true +tar.workspace = true +toml.workspace = true diff --git a/src/tools/cargo/ci/validate-man.sh b/src/tools/cargo/ci/validate-man.sh index 92df49781..a3f114214 100755 --- a/src/tools/cargo/ci/validate-man.sh +++ b/src/tools/cargo/ci/validate-man.sh @@ -3,24 +3,25 @@ set -e -cd src/doc +cargo_man="src/doc" +mdman_man="crates/mdman/doc" -changes=$(git status --porcelain) +changes=$(git status --porcelain -- $cargo_man $mdman_man) if [ -n "$changes" ] then echo "git directory must be clean before running this script." exit 1 fi -./build-man.sh +cargo build-man -changes=$(git status --porcelain) +changes=$(git status --porcelain -- $cargo_man $mdman_man) if [ -n "$changes" ] then - echo "Detected changes in man pages:" + echo "Detected changes of man pages:" echo "$changes" echo - echo "Please run './build-man.sh' in the src/doc directory to rebuild the" - echo "man pages, and commit the changes." + echo 'Please run `cargo build-man` to rebuild the man pages' + echo "and commit the changes." exit 1 fi diff --git a/src/tools/cargo/ci/validate-version-bump.sh b/src/tools/cargo/ci/validate-version-bump.sh new file mode 100755 index 000000000..9b54fdaaf --- /dev/null +++ b/src/tools/cargo/ci/validate-version-bump.sh @@ -0,0 +1,61 @@ +#!/bin/bash +# This script checks if a crate needs a version bump. +# +# At the time of writing, it doesn't check what kind of bump is required. +# In the future, we could take SemVer compatibliity into account, like +# integrating `cargo-semver-checks` of else +# +# Inputs: +# BASE_SHA The commit SHA of the branch where the PR wants to merge into. +# HEAD_SHA The commit SHA that triggered the workflow. + +set -euo pipefail + +# When `BASE_SHA` is missing, we assume it is from bors merge commit, +# so hope `HEAD~` to find the previous commit on master branch. +base_sha=$(git rev-parse "${BASE_SHA:-HEAD~1}") +head_sha=$(git rev-parse "${HEAD_SHA:-HEAD}") + +echo "Base branch is $base_sha" +echo "Current head is $head_sha" + +# Gets crate names of members that has been changed from $bash_sha to $head_sha. +changed_crates=$( + git diff --name-only "$base_sha" "$head_sha" -- crates/ credential/ benches/ \ + | cut -d'/' -f2 \ + | sort -u +) + +if [ -z "$changed_crates" ] +then + echo "No file changed in member crates." + exit 0 +fi + +# Checks publish status for only crates with code changes. +publish_status_table=$( + echo "$changed_crates" \ + | xargs printf -- '--package %s\n' \ + | xargs cargo unpublished +) + +# "yes" -> code changed but no version difference -> need a bump +# Prints 2nd column (sep by space), which is the name of the crate. +crates_need_bump=$( + echo "$publish_status_table" \ + | { grep '| yes ' || true; } \ + | awk '{print $2}' +) + +if [ -z "$crates_need_bump" ] +then + echo "No version bump needed for member crates." + exit 0 +fi + +echo "Detected changes in these crates but no version bump found:" +echo "$crates_need_bump" +echo +echo "Please bump at least one patch version for each corresponding Cargo.toml:" +echo 'Run "cargo unpublished" to read the publish status table for details.' +exit 1 diff --git a/src/tools/cargo/crates/cargo-platform/Cargo.toml b/src/tools/cargo/crates/cargo-platform/Cargo.toml index a5e51ee5d..423cf491d 100644 --- a/src/tools/cargo/crates/cargo-platform/Cargo.toml +++ b/src/tools/cargo/crates/cargo-platform/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cargo-platform" -version = "0.1.2" +version = "0.1.3" edition = "2021" license = "MIT OR Apache-2.0" homepage = "https://github.com/rust-lang/cargo" @@ -9,4 +9,4 @@ documentation = "https://docs.rs/cargo-platform" description = "Cargo's representation of a target platform." [dependencies] -serde = "1.0.82" +serde.workspace = true diff --git a/src/tools/cargo/crates/cargo-test-macro/Cargo.toml b/src/tools/cargo/crates/cargo-test-macro/Cargo.toml index 04dafc028..e40602ae3 100644 --- a/src/tools/cargo/crates/cargo-test-macro/Cargo.toml +++ b/src/tools/cargo/crates/cargo-test-macro/Cargo.toml @@ -7,6 +7,7 @@ homepage = "https://github.com/rust-lang/cargo" repository = "https://github.com/rust-lang/cargo" documentation = "https://github.com/rust-lang/cargo" description = "Helper proc-macro for Cargo's testsuite." +publish = false [lib] proc-macro = true diff --git a/src/tools/cargo/crates/cargo-test-support/Cargo.toml b/src/tools/cargo/crates/cargo-test-support/Cargo.toml index 91e6e4e34..305c809a8 100644 --- a/src/tools/cargo/crates/cargo-test-support/Cargo.toml +++ b/src/tools/cargo/crates/cargo-test-support/Cargo.toml @@ -3,30 +3,31 @@ name = "cargo-test-support" version = "0.1.0" license = "MIT OR Apache-2.0" edition = "2021" +publish = false [lib] doctest = false [dependencies] -anyhow = "1.0.34" -cargo-test-macro = { path = "../cargo-test-macro" } -cargo-util = { path = "../cargo-util" } -crates-io = { path = "../crates-io" } -filetime = "0.2" -flate2 = { version = "1.0", default-features = false, features = ["zlib"] } -git2 = "0.17.0" -glob = "0.3" -itertools = "0.10.0" -lazy_static = "1.0" -pasetors = { version = "0.6.4", features = ["v3", "paserk", "std", "serde"] } -serde = { version = "1.0.123", features = ["derive"] } -serde_json = "1.0" -snapbox = { version = "0.4.0", features = ["diff", "path"] } -tar = { version = "0.4.38", default-features = false } -termcolor = "1.1.2" -time = { version = "0.3", features = ["parsing", "formatting"]} -toml = "0.7.0" -url = "2.2.2" +anyhow.workspace = true +cargo-test-macro.workspace = true +cargo-util.workspace = true +crates-io.workspace = true +filetime.workspace = true +flate2.workspace = true +git2.workspace = true +glob.workspace = true +itertools.workspace = true +lazy_static.workspace = true +pasetors.workspace = true +serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true +snapbox.workspace = true +tar.workspace = true +termcolor.workspace = true +time.workspace = true +toml.workspace = true +url.workspace = true [target.'cfg(windows)'.dependencies] -windows-sys = { version = "0.45.0", features = ["Win32_Storage_FileSystem"] } +windows-sys = { workspace = true, features = ["Win32_Storage_FileSystem"] } diff --git a/src/tools/cargo/crates/cargo-test-support/src/install.rs b/src/tools/cargo/crates/cargo-test-support/src/install.rs index 478b482d2..02842ef7b 100644 --- a/src/tools/cargo/crates/cargo-test-support/src/install.rs +++ b/src/tools/cargo/crates/cargo-test-support/src/install.rs @@ -4,8 +4,12 @@ use std::path::{Path, PathBuf}; /// Used by `cargo install` tests to assert an executable binary /// has been installed. Example usage: +/// ```no_run +/// use cargo_test_support::install::assert_has_installed_exe; +/// use cargo_test_support::install::cargo_home; /// -/// assert_has_installed_exe(cargo_home(), "foo"); +/// assert_has_installed_exe(cargo_home(), "foo"); +/// ``` #[track_caller] pub fn assert_has_installed_exe<P: AsRef<Path>>(path: P, name: &'static str) { assert!(check_has_installed_exe(path, name)); diff --git a/src/tools/cargo/crates/cargo-test-support/src/lib.rs b/src/tools/cargo/crates/cargo-test-support/src/lib.rs index 04d6ce9f8..d27aab44f 100644 --- a/src/tools/cargo/crates/cargo-test-support/src/lib.rs +++ b/src/tools/cargo/crates/cargo-test-support/src/lib.rs @@ -59,8 +59,8 @@ pub fn panic_error(what: &str, err: impl Into<anyhow::Error>) -> ! { 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)); + let _ = writeln!(result, "\nCaused by:"); + let _ = write!(result, "{}", cause); } panic!("\n{}", result); } @@ -517,6 +517,29 @@ pub fn cargo_exe() -> PathBuf { snapbox::cmd::cargo_bin("cargo") } +/// A wrapper around `rustc` instead of calling `clippy`. +pub fn wrapped_clippy_driver() -> PathBuf { + let clippy_driver = project() + .at(paths::global_root().join("clippy-driver")) + .file("Cargo.toml", &basic_manifest("clippy-driver", "0.0.1")) + .file( + "src/main.rs", + r#" + fn main() { + let mut args = std::env::args_os(); + let _me = args.next().unwrap(); + let rustc = args.next().unwrap(); + let status = std::process::Command::new(rustc).args(args).status().unwrap(); + std::process::exit(status.code().unwrap_or(1)); + } + "#, + ) + .build(); + clippy_driver.cargo("build").run(); + + clippy_driver.bin("clippy-driver") +} + /// This is the raw output from the process. /// /// This is similar to `std::process::Output`, however the `status` is @@ -677,13 +700,15 @@ impl Execs { /// The substrings are matched as `contains`. Example: /// /// ```no_run - /// execs.with_stderr_line_without( + /// use cargo_test_support::execs; + /// + /// execs().with_stderr_line_without( /// &[ /// "[RUNNING] `rustc --crate-name build_script_build", /// "-C opt-level=3", /// ], /// &["-C debuginfo", "-C incremental"], - /// ) + /// ); /// ``` /// /// This will check that a build line includes `-C opt-level=3` but does diff --git a/src/tools/cargo/crates/cargo-test-support/src/publish.rs b/src/tools/cargo/crates/cargo-test-support/src/publish.rs index 64774bc43..dccc8356d 100644 --- a/src/tools/cargo/crates/cargo-test-support/src/publish.rs +++ b/src/tools/cargo/crates/cargo-test-support/src/publish.rs @@ -165,6 +165,7 @@ pub(crate) fn create_index_line( features: crate::registry::FeatureMap, yanked: bool, links: Option<String>, + rust_version: Option<&str>, v: Option<u32>, ) -> String { // This emulates what crates.io does to retain backwards compatibility. @@ -185,6 +186,9 @@ pub(crate) fn create_index_line( if let Some(v) = v { json["v"] = serde_json::json!(v); } + if let Some(rust_version) = rust_version { + json["rust_version"] = serde_json::json!(rust_version); + } json.to_string() } diff --git a/src/tools/cargo/crates/cargo-test-support/src/registry.rs b/src/tools/cargo/crates/cargo-test-support/src/registry.rs index 5faf23540..0cf82cb70 100644 --- a/src/tools/cargo/crates/cargo-test-support/src/registry.rs +++ b/src/tools/cargo/crates/cargo-test-support/src/registry.rs @@ -450,7 +450,10 @@ impl RegistryBuilder { /// `VendorPackage` which implements directory sources. /// /// # Example -/// ``` +/// ```no_run +/// use cargo_test_support::registry::Package; +/// use cargo_test_support::project; +/// /// // Publish package "a" depending on "b". /// Package::new("a", "1.0.0") /// .dep("b", "1.0.0") @@ -1144,6 +1147,7 @@ fn save_new_crate( false, new_crate.links, None, + None, ); write_to_index(registry_path, &new_crate.name, line, false); @@ -1240,7 +1244,7 @@ impl Package { } /// Adds a normal dependency. Example: - /// ``` + /// ```toml /// [dependencies] /// foo = {version = "1.0"} /// ``` @@ -1249,7 +1253,7 @@ impl Package { } /// Adds a dependency with the given feature. Example: - /// ``` + /// ```toml /// [dependencies] /// foo = {version = "1.0", "features": ["feat1", "feat2"]} /// ``` @@ -1272,7 +1276,7 @@ impl Package { } /// Adds a dev-dependency. Example: - /// ``` + /// ```toml /// [dev-dependencies] /// foo = {version = "1.0"} /// ``` @@ -1281,7 +1285,7 @@ impl Package { } /// Adds a build-dependency. Example: - /// ``` + /// ```toml /// [build-dependencies] /// foo = {version = "1.0"} /// ``` @@ -1400,6 +1404,7 @@ impl Package { self.features.clone(), self.yanked, self.links.clone(), + self.rust_version.as_deref(), self.v, ); diff --git a/src/tools/cargo/crates/cargo-util/Cargo.toml b/src/tools/cargo/crates/cargo-util/Cargo.toml index 7427ceb1a..f01705fca 100644 --- a/src/tools/cargo/crates/cargo-util/Cargo.toml +++ b/src/tools/cargo/crates/cargo-util/Cargo.toml @@ -8,21 +8,21 @@ repository = "https://github.com/rust-lang/cargo" description = "Miscellaneous support code used by Cargo." [dependencies] -anyhow = "1.0.34" -sha2 = "0.10.6" -filetime = "0.2.9" -hex = "0.4.2" -jobserver = "0.1.26" -libc = "0.2.88" -log = "0.4.6" -same-file = "1.0.6" -shell-escape = "0.1.4" -tempfile = "3.1.0" -walkdir = "2.3.1" +anyhow.workspace = true +sha2.workspace = true +filetime.workspace = true +hex.workspace = true +jobserver.workspace = true +libc.workspace = true +log.workspace = true +same-file.workspace = true +shell-escape.workspace = true +tempfile.workspace = true +walkdir.workspace = true [target.'cfg(target_os = "macos")'.dependencies] -core-foundation = { version = "0.9.0", features = ["mac_os_10_7_support"] } +core-foundation.workspace = true [target.'cfg(windows)'.dependencies] -miow = "0.5.0" -windows-sys = { version = "0.45.0", features = ["Win32_Storage_FileSystem", "Win32_Foundation", "Win32_System_Console"] } +miow.workspace = true +windows-sys = { workspace = true, features = ["Win32_Storage_FileSystem", "Win32_Foundation", "Win32_System_Console"] } diff --git a/src/tools/cargo/crates/crates-io/Cargo.toml b/src/tools/cargo/crates/crates-io/Cargo.toml index 004e2daff..034c2fca5 100644 --- a/src/tools/cargo/crates/crates-io/Cargo.toml +++ b/src/tools/cargo/crates/crates-io/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "crates-io" -version = "0.36.0" +version = "0.37.0" edition = "2021" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/cargo" @@ -13,9 +13,9 @@ name = "crates_io" path = "lib.rs" [dependencies] -anyhow = "1.0.34" -curl = "0.4" -percent-encoding = "2.0" -serde = { version = "1.0", features = ['derive'] } -serde_json = "1.0" -url = "2.0" +anyhow.workspace = true +curl.workspace = true +percent-encoding.workspace = true +serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true +url.workspace = true diff --git a/src/tools/cargo/crates/crates-io/lib.rs b/src/tools/cargo/crates/crates-io/lib.rs index e0197568a..243808098 100644 --- a/src/tools/cargo/crates/crates-io/lib.rs +++ b/src/tools/cargo/crates/crates-io/lib.rs @@ -57,6 +57,7 @@ pub struct NewCrate { pub repository: Option<String>, pub badges: BTreeMap<String, BTreeMap<String, String>>, pub links: Option<String>, + pub rust_version: Option<String>, } #[derive(Serialize, Deserialize)] @@ -199,7 +200,7 @@ impl Registry { /// let mut handle = Easy::new(); /// // If connecting to crates.io, a user-agent is required. /// handle.useragent("my_crawler (example.com/info)"); - /// let mut reg = Registry::new_handle(String::from("https://crates.io"), None, handle); + /// let mut reg = Registry::new_handle(String::from("https://crates.io"), None, handle, true); /// ``` pub fn new_handle( host: String, diff --git a/src/tools/cargo/crates/credential/cargo-credential-macos-keychain/src/main.rs b/src/tools/cargo/crates/credential/cargo-credential-macos-keychain/src/main.rs deleted file mode 100644 index 3fef3f92a..000000000 --- a/src/tools/cargo/crates/credential/cargo-credential-macos-keychain/src/main.rs +++ /dev/null @@ -1,50 +0,0 @@ -//! Cargo registry macos keychain credential process. - -use cargo_credential::{Credential, Error}; -use security_framework::os::macos::keychain::SecKeychain; - -struct MacKeychain; - -/// The account name is not used. -const ACCOUNT: &'static str = ""; - -fn registry(registry_name: &str) -> String { - format!("cargo-registry:{}", registry_name) -} - -impl Credential for MacKeychain { - fn name(&self) -> &'static str { - env!("CARGO_PKG_NAME") - } - - fn get(&self, index_url: &str) -> Result<String, Error> { - let keychain = SecKeychain::default().unwrap(); - let service_name = registry(index_url); - let (pass, _item) = keychain.find_generic_password(&service_name, ACCOUNT)?; - String::from_utf8(pass.as_ref().to_vec()) - .map_err(|_| "failed to convert token to UTF8".into()) - } - - fn store(&self, index_url: &str, token: &str, name: Option<&str>) -> Result<(), Error> { - let keychain = SecKeychain::default().unwrap(); - let service_name = registry(name.unwrap_or(index_url)); - if let Ok((_pass, mut item)) = keychain.find_generic_password(&service_name, ACCOUNT) { - item.set_password(token.as_bytes())?; - } else { - keychain.add_generic_password(&service_name, ACCOUNT, token.as_bytes())?; - } - Ok(()) - } - - fn erase(&self, index_url: &str) -> Result<(), Error> { - let keychain = SecKeychain::default().unwrap(); - let service_name = registry(index_url); - let (_pass, item) = keychain.find_generic_password(&service_name, ACCOUNT)?; - item.delete(); - Ok(()) - } -} - -fn main() { - cargo_credential::main(MacKeychain); -} diff --git a/src/tools/cargo/crates/credential/cargo-credential-wincred/src/main.rs b/src/tools/cargo/crates/credential/cargo-credential-wincred/src/main.rs deleted file mode 100644 index 8ae48f348..000000000 --- a/src/tools/cargo/crates/credential/cargo-credential-wincred/src/main.rs +++ /dev/null @@ -1,111 +0,0 @@ -//! Cargo registry windows credential process. - -use cargo_credential::{Credential, Error}; -use std::ffi::OsStr; -use std::os::windows::ffi::OsStrExt; - -use windows_sys::core::PWSTR; -use windows_sys::Win32::Foundation::ERROR_NOT_FOUND; -use windows_sys::Win32::Foundation::FILETIME; -use windows_sys::Win32::Foundation::TRUE; -use windows_sys::Win32::Security::Credentials::CredDeleteW; -use windows_sys::Win32::Security::Credentials::CredReadW; -use windows_sys::Win32::Security::Credentials::CredWriteW; -use windows_sys::Win32::Security::Credentials::CREDENTIALW; -use windows_sys::Win32::Security::Credentials::CRED_PERSIST_LOCAL_MACHINE; -use windows_sys::Win32::Security::Credentials::CRED_TYPE_GENERIC; - -struct WindowsCredential; - -/// Converts a string to a nul-terminated wide UTF-16 byte sequence. -fn wstr(s: &str) -> Vec<u16> { - let mut wide: Vec<u16> = OsStr::new(s).encode_wide().collect(); - if wide.iter().any(|b| *b == 0) { - panic!("nul byte in wide string"); - } - wide.push(0); - wide -} - -fn target_name(registry_name: &str) -> Vec<u16> { - wstr(&format!("cargo-registry:{}", registry_name)) -} - -impl Credential for WindowsCredential { - fn name(&self) -> &'static str { - env!("CARGO_PKG_NAME") - } - - fn get(&self, index_url: &str) -> Result<String, Error> { - let target_name = target_name(index_url); - let p_credential: *mut CREDENTIALW = std::ptr::null_mut() as *mut _; - unsafe { - if CredReadW( - target_name.as_ptr(), - CRED_TYPE_GENERIC, - 0, - p_credential as *mut _ as *mut _, - ) != TRUE - { - return Err( - format!("failed to fetch token: {}", std::io::Error::last_os_error()).into(), - ); - } - let bytes = std::slice::from_raw_parts( - (*p_credential).CredentialBlob, - (*p_credential).CredentialBlobSize as usize, - ); - String::from_utf8(bytes.to_vec()).map_err(|_| "failed to convert token to UTF8".into()) - } - } - - fn store(&self, index_url: &str, token: &str, name: Option<&str>) -> Result<(), Error> { - let token = token.as_bytes(); - let target_name = target_name(index_url); - let comment = match name { - Some(name) => wstr(&format!("Cargo registry token for {}", name)), - None => wstr("Cargo registry token"), - }; - let mut credential = CREDENTIALW { - Flags: 0, - Type: CRED_TYPE_GENERIC, - TargetName: target_name.as_ptr() as PWSTR, - Comment: comment.as_ptr() as PWSTR, - LastWritten: FILETIME { - dwLowDateTime: 0, - dwHighDateTime: 0, - }, - CredentialBlobSize: token.len() as u32, - CredentialBlob: token.as_ptr() as *mut u8, - Persist: CRED_PERSIST_LOCAL_MACHINE, - AttributeCount: 0, - Attributes: std::ptr::null_mut(), - TargetAlias: std::ptr::null_mut(), - UserName: std::ptr::null_mut(), - }; - let result = unsafe { CredWriteW(&mut credential, 0) }; - if result != TRUE { - let err = std::io::Error::last_os_error(); - return Err(format!("failed to store token: {}", err).into()); - } - Ok(()) - } - - fn erase(&self, index_url: &str) -> Result<(), Error> { - let target_name = target_name(index_url); - let result = unsafe { CredDeleteW(target_name.as_ptr(), CRED_TYPE_GENERIC, 0) }; - if result != TRUE { - let err = std::io::Error::last_os_error(); - if err.raw_os_error() == Some(ERROR_NOT_FOUND as i32) { - eprintln!("not currently logged in to `{}`", index_url); - return Ok(()); - } - return Err(format!("failed to remove token: {}", err).into()); - } - Ok(()) - } -} - -fn main() { - cargo_credential::main(WindowsCredential); -} diff --git a/src/tools/cargo/crates/home/CHANGELOG.md b/src/tools/cargo/crates/home/CHANGELOG.md index 7674667c9..58f960cc3 100644 --- a/src/tools/cargo/crates/home/CHANGELOG.md +++ b/src/tools/cargo/crates/home/CHANGELOG.md @@ -4,7 +4,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -<!-- ## [Unreleased] --> +## 0.5.6 +- Fixed & enhanced documentation. + [#12047](https://github.com/rust-lang/cargo/pull/12047) + +## 0.5.5 - 2023-04-25 +- The `home` crate has migrated to the <https://github.com/rust-lang/cargo/> repository. + [#11359](https://github.com/rust-lang/cargo/pull/11359) +- Replaced the winapi dependency with windows-sys. + [#11656](https://github.com/rust-lang/cargo/pull/11656) ## [0.5.4] - 2022-10-10 - Add `_with_env` variants of functions to support in-process threaded tests for @@ -38,7 +46,6 @@ Use Rust 1.36.0 as minimum Rust version. ### Removed - Remove support for `multirust` folder used in old version of `rustup`. -[Unreleased]: https://github.com/brson/home/compare/v0.5.4...HEAD [0.5.4]: https://github.com/brson/home/compare/v0.5.3...v0.5.4 [0.5.3]: https://github.com/brson/home/compare/v0.5.2...v0.5.3 [0.5.2]: https://github.com/brson/home/compare/v0.5.1...v0.5.2 diff --git a/src/tools/cargo/crates/home/Cargo.toml b/src/tools/cargo/crates/home/Cargo.toml index 2c5b92bcb..6c65ecc18 100644 --- a/src/tools/cargo/crates/home/Cargo.toml +++ b/src/tools/cargo/crates/home/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "home" -version = "0.5.4" # also update `html_root_url` in `src/lib.rs` +version = "0.5.6" # also update `html_root_url` in `src/lib.rs` authors = ["Brian Anderson <andersrb@gmail.com>"] documentation = "https://docs.rs/home" edition = "2018" @@ -17,4 +17,4 @@ repository = "https://github.com/rust-lang/cargo" description = "Shared definitions of home directories." [target.'cfg(windows)'.dependencies] -windows-sys = { version = "0.45.0", features = ["Win32_Foundation", "Win32_UI_Shell"] } +windows-sys = { workspace = true, features = ["Win32_Foundation", "Win32_UI_Shell"] } diff --git a/src/tools/cargo/crates/home/src/env.rs b/src/tools/cargo/crates/home/src/env.rs index e47273bc8..49fea5422 100644 --- a/src/tools/cargo/crates/home/src/env.rs +++ b/src/tools/cargo/crates/home/src/env.rs @@ -9,7 +9,7 @@ use std::{ /// Permits parameterizing the home functions via the _from variants - used for /// in-process unit testing by rustup. pub trait Env { - /// Return the path to the the users home dir, or None if any error occurs: + /// Return the path to the users home dir, or None if any error occurs: /// see home_inner. fn home_dir(&self) -> Option<PathBuf>; /// Return the current working directory. diff --git a/src/tools/cargo/crates/home/src/lib.rs b/src/tools/cargo/crates/home/src/lib.rs index 306026e40..0e1e975e4 100644 --- a/src/tools/cargo/crates/home/src/lib.rs +++ b/src/tools/cargo/crates/home/src/lib.rs @@ -1,14 +1,5 @@ //! Canonical definitions of `home_dir`, `cargo_home`, and `rustup_home`. //! -//! This provides the definition of `home_dir` used by Cargo and -//! rustup, as well functions to find the correct value of -//! `CARGO_HOME` and `RUSTUP_HOME`. -//! -//! See also the [`dirs`](https://docs.rs/dirs) crate. -//! -//! _Note that as of 2019/08/06 it appears that cargo uses this crate. And -//! rustup has used this crate since 2019/08/21._ -//! //! The definition of `home_dir` provided by the standard library is //! incorrect because it considers the `HOME` environment variable on //! Windows. This causes surprising situations where a Rust program @@ -17,15 +8,17 @@ //! rustup use the standard libraries definition - they use the //! definition here. //! -//! This crate further provides two functions, `cargo_home` and +//! This crate provides two additional functions, `cargo_home` and //! `rustup_home`, which are the canonical way to determine the -//! location that Cargo and rustup store their data. +//! location that Cargo and rustup use to store their data. +//! The `env` module contains utilities for mocking the process environment +//! by Cargo and rustup. //! //! See also this [discussion]. //! //! [discussion]: https://github.com/rust-lang/rust/pull/46799#issuecomment-361156935 -#![doc(html_root_url = "https://docs.rs/home/0.5.4")] +#![doc(html_root_url = "https://docs.rs/home/0.5.6")] #![deny(rust_2018_idioms)] pub mod env; @@ -36,29 +29,34 @@ mod windows; use std::io; use std::path::{Path, PathBuf}; -/// Returns the path of the current user's home directory if known. +/// Returns the path of the current user's home directory using environment +/// variables or OS-specific APIs. /// /// # Unix /// /// Returns the value of the `HOME` environment variable if it is set -/// and not equal to the empty string. Otherwise, it tries to determine the -/// home directory by invoking the `getpwuid_r` function on the UID of the -/// current user. +/// **even** if it is an empty string. Otherwise, it tries to determine the +/// home directory by invoking the [`getpwuid_r`][getpwuid] function with +/// the UID of the current user. +/// +/// [getpwuid]: https://linux.die.net/man/3/getpwuid_r /// /// # Windows /// -/// Returns the value of the `USERPROFILE` environment variable if it -/// is set and not equal to the empty string. If both do not exist, -/// [`SHGetFolderPathW`][msdn] is used to return the appropriate path. +/// Returns the value of the `USERPROFILE` environment variable if it is set +/// **and** it is not an empty string. Otherwise, it tries to determine the +/// home directory by invoking the [`SHGetFolderPathW`][shgfp] function with +/// [`CSIDL_PROFILE`][csidl]. /// -/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetfolderpathw +/// [shgfp]: https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetfolderpathw +/// [csidl]: https://learn.microsoft.com/en-us/windows/win32/shell/csidl /// /// # Examples /// /// ``` /// match home::home_dir() { -/// Some(path) => println!("{}", path.display()), -/// None => println!("Impossible to get your home dir!"), +/// Some(path) if !path.as_os_str().is_empty() => println!("{}", path.display()), +/// _ => println!("Unable to get your home dir!"), /// } /// ``` pub fn home_dir() -> Option<PathBuf> { diff --git a/src/tools/cargo/crates/mdman/Cargo.lock b/src/tools/cargo/crates/mdman/Cargo.lock deleted file mode 100644 index 51fe47a9c..000000000 --- a/src/tools/cargo/crates/mdman/Cargo.lock +++ /dev/null @@ -1,459 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anyhow" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array", -] - -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", -] - -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - -[[package]] -name = "byteorder" -version = "1.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "ctor" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39858aa5bac06462d4dd4b9164848eb81ffc4aa5c479746393598fd193afa227" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "diff" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" - -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - -[[package]] -name = "form_urlencoded" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" -dependencies = [ - "matches", - "percent-encoding", -] - -[[package]] -name = "generic-array" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -dependencies = [ - "typenum", -] - -[[package]] -name = "handlebars" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86dbc8a0746b08f363d2e00da48e6c9ceb75c198ac692d2715fcbb5bee74c87d" -dependencies = [ - "log", - "pest", - "pest_derive", - "quick-error", - "serde", - "serde_json", - "walkdir", -] - -[[package]] -name = "idna" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "itoa" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" - -[[package]] -name = "log" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "maplit" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" - -[[package]] -name = "matches" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" - -[[package]] -name = "mdman" -version = "0.1.0" -dependencies = [ - "anyhow", - "handlebars", - "pretty_assertions", - "pulldown-cmark", - "same-file", - "serde_json", - "url", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - -[[package]] -name = "output_vt100" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" -dependencies = [ - "winapi", -] - -[[package]] -name = "percent-encoding" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" - -[[package]] -name = "pest" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" -dependencies = [ - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pest_meta" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" -dependencies = [ - "maplit", - "pest", - "sha-1", -] - -[[package]] -name = "pretty_assertions" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" -dependencies = [ - "ctor", - "diff", - "output_vt100", - "yansi", -] - -[[package]] -name = "proc-macro2" -version = "1.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "pulldown-cmark" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63" -dependencies = [ - "bitflags", - "memchr", - "unicase", -] - -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - -[[package]] -name = "quote" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "ryu" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "serde" -version = "1.0.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" - -[[package]] -name = "serde_json" -version = "1.0.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha-1" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" -dependencies = [ - "block-buffer", - "digest", - "fake-simd", - "opaque-debug", -] - -[[package]] -name = "syn" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cdb98bcb1f9d81d07b536179c269ea15999b5d14ea958196413869445bb5250" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "tinyvec" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53953d2d3a5ad81d9f844a32f14ebb121f50b650cd59d0ee2a07cf13c617efed" - -[[package]] -name = "typenum" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" - -[[package]] -name = "ucd-trie" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" - -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -dependencies = [ - "matches", -] - -[[package]] -name = "unicode-normalization" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-xid" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" - -[[package]] -name = "url" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" -dependencies = [ - "form_urlencoded", - "idna", - "matches", - "percent-encoding", -] - -[[package]] -name = "version_check" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" - -[[package]] -name = "walkdir" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "yansi" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" diff --git a/src/tools/cargo/crates/mdman/Cargo.toml b/src/tools/cargo/crates/mdman/Cargo.toml index 92cdf2eb6..812f1393a 100644 --- a/src/tools/cargo/crates/mdman/Cargo.toml +++ b/src/tools/cargo/crates/mdman/Cargo.toml @@ -1,17 +1,18 @@ [package] name = "mdman" -version = "0.1.0" +version = "0.0.0" edition = "2021" license = "MIT OR Apache-2.0" description = "Creates a man page page from markdown." +publish = false [dependencies] -anyhow = "1.0.31" -handlebars = { version = "3.2.1", features = ["dir_source"] } -pulldown-cmark = { version = "0.9.2", default-features = false } -same-file = "1.0.6" -serde_json = "1.0.56" -url = "2.2.2" +anyhow.workspace = true +handlebars.workspace = true +pulldown-cmark.workspace = true +same-file.workspace = true +serde_json.workspace = true +url.workspace = true [dev-dependencies] -pretty_assertions = "1.3.0" +pretty_assertions.workspace = true diff --git a/src/tools/cargo/crates/mdman/build-man.sh b/src/tools/cargo/crates/mdman/build-man.sh deleted file mode 100755 index 9286b17c2..000000000 --- a/src/tools/cargo/crates/mdman/build-man.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -set -e - -cargo run -- -t md -o doc/out doc/*.md -cargo run -- -t txt -o doc/out doc/*.md -cargo run -- -t man -o doc/out doc/*.md diff --git a/src/tools/cargo/crates/mdman/doc/mdman.md b/src/tools/cargo/crates/mdman/doc/mdman.md index 2025c13dc..bfa394648 100644 --- a/src/tools/cargo/crates/mdman/doc/mdman.md +++ b/src/tools/cargo/crates/mdman/doc/mdman.md @@ -28,7 +28,7 @@ man page: and `{{/options}}` tags. This tells the processor where the options start and end. - Each option must be expressed with a `{{#option}}` block. The parameters to - the the block are a sequence of strings indicating the option. For example, + the block are a sequence of strings indicating the option. For example, ```{{#option "`-p` _spec_..." "`--package` _spec_..."}}``` is an option that has two different forms. The text within the string is processed as markdown. It is recommended to use formatting similar to this example. diff --git a/src/tools/cargo/crates/mdman/doc/out/mdman.1 b/src/tools/cargo/crates/mdman/doc/out/mdman.1 index 0718d6ddb..b114715ae 100644 --- a/src/tools/cargo/crates/mdman/doc/out/mdman.1 +++ b/src/tools/cargo/crates/mdman/doc/out/mdman.1 @@ -6,7 +6,7 @@ .SH "NAME" mdman \- Converts markdown to a man page .SH "SYNOPSIS" -\fBmdman\fR [\fIoptions\fR] \fB\-t\fR \fItype\fR \fB\-o\fR \fIoutdir\fR \fIsources...\fR +\fBmdman\fR [\fIoptions\fR] \fB\-t\fR \fItype\fR \fB\-o\fR \fIoutdir\fR \fIsources\[u2026]\fR .SH "DESCRIPTION" Converts a markdown file to a man page. .sp @@ -29,7 +29,7 @@ and end. .sp .RS 4 \h'-04'\(bu\h'+02'Each option must be expressed with a \fB{{#option}}\fR block. The parameters to -the the block are a sequence of strings indicating the option. For example, +the block are a sequence of strings indicating the option. For example, \fB{{#option "`\-p` _spec_..." "`\-\-package` _spec_..."}}\fR is an option that has two different forms. The text within the string is processed as markdown. It is recommended to use formatting similar to this example. @@ -83,7 +83,7 @@ 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\[cq]t available. Outputs with the \fB\&.txt\fR extension. .RE .RE @@ -107,7 +107,7 @@ matching \fB\-\-man\fR entry, then a relative link to a file named \fIname\fR\fB be used. .RE .sp -\fIsources...\fR +\fIsources\[u2026]\fR .RS 4 The source input filename, may be specified multiple times. .RE diff --git a/src/tools/cargo/crates/mdman/doc/out/mdman.md b/src/tools/cargo/crates/mdman/doc/out/mdman.md index d0dd34511..9d2fe9326 100644 --- a/src/tools/cargo/crates/mdman/doc/out/mdman.md +++ b/src/tools/cargo/crates/mdman/doc/out/mdman.md @@ -27,7 +27,7 @@ man page: and `{{/options}}` tags. This tells the processor where the options start and end. - Each option must be expressed with a `{{#option}}` block. The parameters to - the the block are a sequence of strings indicating the option. For example, + the block are a sequence of strings indicating the option. For example, ```{{#option "`-p` _spec_..." "`--package` _spec_..."}}``` is an option that has two different forms. The text within the string is processed as markdown. It is recommended to use formatting similar to this example. @@ -61,7 +61,7 @@ man page: <code>.1</code>) matching the man page section.</li> <li><code>md</code> — A markdown file, after all handlebars processing has been finished. Outputs with the <code>.md</code> extension.</li> -<li><code>txt</code> — A text file, rendered for situations where a man page viewer isn't +<li><code>txt</code> — A text file, rendered for situations where a man page viewer isn’t available. Outputs with the <code>.txt</code> extension.</li> </ul></dd> @@ -82,7 +82,7 @@ matching <code>--man</code> entry, then a relative link to a file named <em>name be used.</dd> -<dt class="option-term" id="option-mdman-sources..."><a class="option-anchor" href="#option-mdman-sources..."></a><em>sources...</em></dt> +<dt class="option-term" id="option-mdman-sources…"><a class="option-anchor" href="#option-mdman-sources…"></a><em>sources…</em></dt> <dd class="option-desc">The source input filename, may be specified multiple times.</dd> diff --git a/src/tools/cargo/crates/mdman/doc/out/mdman.txt b/src/tools/cargo/crates/mdman/doc/out/mdman.txt index 83fa7de90..6c8dcd65d 100644 --- a/src/tools/cargo/crates/mdman/doc/out/mdman.txt +++ b/src/tools/cargo/crates/mdman/doc/out/mdman.txt @@ -4,7 +4,7 @@ NAME mdman - Converts markdown to a man page SYNOPSIS - mdman [options] -t type -o outdir sources... + mdman [options] -t type -o outdir sources… DESCRIPTION Converts a markdown file to a man page. @@ -25,7 +25,7 @@ DESCRIPTION the options start and end. o Each option must be expressed with a {{#option}} block. The - parameters to the the block are a sequence of strings indicating the + parameters to the block are a sequence of strings indicating the option. For example, {{#option "`-p` _spec_..." "`--package` _spec_..."}} is an option that has two different forms. The text within the string is processed as markdown. It is recommended to use @@ -65,7 +65,7 @@ OPTIONS finished. Outputs with the .md extension. o txt — A text file, rendered for situations where a man page - viewer isn't available. Outputs with the .txt extension. + viewer isn’t available. Outputs with the .txt extension. -o outdir Specifies the directory where to save the output. @@ -81,7 +81,7 @@ OPTIONS does not have a matching --man entry, then a relative link to a file named name.md will be used. - sources... + sources… The source input filename, may be specified multiple times. EXAMPLES diff --git a/src/tools/cargo/crates/resolver-tests/Cargo.toml b/src/tools/cargo/crates/resolver-tests/Cargo.toml index e4aab4325..8a7cab113 100644 --- a/src/tools/cargo/crates/resolver-tests/Cargo.toml +++ b/src/tools/cargo/crates/resolver-tests/Cargo.toml @@ -1,12 +1,13 @@ [package] name = "resolver-tests" -version = "0.1.0" +version = "0.0.0" edition = "2018" +publish = false [dependencies] -cargo = { path = "../.." } -cargo-util = { path = "../cargo-util" } -is-terminal = "0.4.0" -lazy_static = "1.3.0" -proptest = "1.1.0" -varisat = "0.2.1" +cargo.workspace = true +cargo-util.workspace = true +is-terminal.workspace = true +lazy_static.workspace = true +proptest.workspace = true +varisat.workspace = true diff --git a/src/tools/cargo/crates/resolver-tests/src/lib.rs b/src/tools/cargo/crates/resolver-tests/src/lib.rs index 3ffb6c5d2..01d9b5e6d 100644 --- a/src/tools/cargo/crates/resolver-tests/src/lib.rs +++ b/src/tools/cargo/crates/resolver-tests/src/lib.rs @@ -184,6 +184,7 @@ pub fn resolve_with_config_raw( deps, &BTreeMap::new(), None::<&String>, + None::<&String>, ) .unwrap(); let opts = ResolveOpts::everything(); @@ -585,6 +586,7 @@ pub fn pkg_dep<T: ToPkgId>(name: T, dep: Vec<Dependency>) -> Summary { dep, &BTreeMap::new(), link, + None::<&String>, ) .unwrap() } @@ -613,6 +615,7 @@ pub fn pkg_loc(name: &str, loc: &str) -> Summary { Vec::new(), &BTreeMap::new(), link, + None::<&String>, ) .unwrap() } @@ -627,6 +630,7 @@ pub fn remove_dep(sum: &Summary, ind: usize) -> Summary { deps, &BTreeMap::new(), sum.links().map(|a| a.as_str()), + None::<&String>, ) .unwrap() } diff --git a/src/tools/cargo/src/doc/semver-check/Cargo.toml b/src/tools/cargo/crates/semver-check/Cargo.toml index bdfd8d7d7..f7b8c7d48 100644 --- a/src/tools/cargo/src/doc/semver-check/Cargo.toml +++ b/src/tools/cargo/crates/semver-check/Cargo.toml @@ -1,10 +1,11 @@ [package] name = "semver-check" -version = "0.1.0" +version = "0.0.0" authors = ["Eric Huss"] edition = "2021" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -tempfile = "3.1.0" +tempfile.workspace = true diff --git a/src/tools/cargo/src/doc/semver-check/src/main.rs b/src/tools/cargo/crates/semver-check/src/main.rs index 51aacbe11..fa4639eb7 100644 --- a/src/tools/cargo/src/doc/semver-check/src/main.rs +++ b/src/tools/cargo/crates/semver-check/src/main.rs @@ -23,9 +23,13 @@ fn main() { const SEPARATOR: &str = "///////////////////////////////////////////////////////////"; fn doit() -> Result<(), Box<dyn Error>> { - let filename = std::env::args() - .nth(1) - .unwrap_or_else(|| "../src/reference/semver.md".to_string()); + let filename = std::env::args().nth(1).unwrap_or_else(|| { + Path::new(env!("CARGO_MANIFEST_DIR")) + .join("../../src/doc/src/reference/semver.md") + .to_str() + .unwrap() + .to_string() + }); let contents = fs::read_to_string(filename)?; let mut lines = contents.lines().enumerate(); diff --git a/src/tools/cargo/crates/xtask-build-man/Cargo.toml b/src/tools/cargo/crates/xtask-build-man/Cargo.toml new file mode 100644 index 000000000..6d02aa2c3 --- /dev/null +++ b/src/tools/cargo/crates/xtask-build-man/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "xtask-build-man" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies] diff --git a/src/tools/cargo/crates/xtask-build-man/src/main.rs b/src/tools/cargo/crates/xtask-build-man/src/main.rs new file mode 100644 index 000000000..6680c3783 --- /dev/null +++ b/src/tools/cargo/crates/xtask-build-man/src/main.rs @@ -0,0 +1,108 @@ +//! ```text +//! NAME +//! build-man +//! +//! SYNOPSIS +//! build-man +//! +//! DESCRIPTION +//! Build the man pages for packages `mdman` and `cargo`. +//! For more, read their doc comments. +//! ``` + +use std::fs; +use std::io; +use std::path::PathBuf; +use std::process; +use std::process::Command; + +fn main() -> io::Result<()> { + build_mdman()?; + build_cargo()?; + Ok(()) +} + +/// Builds the man pages for `mdman`. +fn build_mdman() -> io::Result<()> { + cwd_to_workspace_root()?; + + let src_paths = &["crates/mdman/doc/mdman.md".into()]; + let dst_path = "crates/mdman/doc/out"; + let outs = [("md", dst_path), ("txt", dst_path), ("man", dst_path)]; + + build_man("mdman", src_paths, &outs, &[]) +} + +/// Builds the man pages for Cargo. +/// +/// The source for the man pages are located in src/doc/man/ in markdown format. +/// These also are handlebars templates, see crates/mdman/README.md for details. +/// +/// The generated man pages are placed in the src/etc/man/ directory. The pages +/// are also expanded into markdown (after being expanded by handlebars) and +/// saved in the src/doc/src/commands/ directory. These are included in the +/// Cargo book, which is converted to HTML by mdbook. +fn build_cargo() -> io::Result<()> { + // Find all `src/doc/man/cargo-*.md` + let src_paths = { + let mut src_paths = Vec::new(); + for entry in fs::read_dir("src/doc/man")? { + let entry = entry?; + let file_name = entry.file_name(); + let file_name = file_name.to_str().unwrap(); + if file_name.starts_with("cargo-") && file_name.ends_with(".md") { + src_paths.push(entry.path()); + } + } + src_paths + }; + let outs = [ + ("md", "src/doc/src/commands"), + ("txt", "src/doc/man/generated_txt"), + ("man", "src/etc/man"), + ]; + let args = [ + "--url", + "https://doc.rust-lang.org/cargo/commands/", + "--man", + "rustc:1=https://doc.rust-lang.org/rustc/index.html", + "--man", + "rustdoc:1=https://doc.rust-lang.org/rustdoc/index.html", + ]; + build_man("cargo", &src_paths[..], &outs, &args) +} + +/// Change to workspace root. +/// +/// Assumed this xtask is located in `[WORKSPACE]/crates/xtask-build-man`. +fn cwd_to_workspace_root() -> io::Result<()> { + let pkg_root = std::env!("CARGO_MANIFEST_DIR"); + let ws_root = format!("{pkg_root}/../.."); + std::env::set_current_dir(ws_root) +} + +/// Builds the man pages. +fn build_man( + pkg_name: &str, + src_paths: &[PathBuf], + outs: &[(&str, &str)], + extra_args: &[&str], +) -> io::Result<()> { + for (format, dst_path) in outs { + eprintln!("Start converting `{format}` for package `{pkg_name}`..."); + let mut cmd = Command::new(std::env!("CARGO")); + cmd.args(["run", "--package", "mdman", "--"]) + .args(["-t", format, "-o", dst_path]) + .args(src_paths) + .args(extra_args); + + let status = cmd.status()?; + if !status.success() { + eprintln!("failed to build the man pages for package `{pkg_name}`"); + eprintln!("failed command: `{cmd:?}`"); + process::exit(status.code().unwrap_or(1)); + } + } + + Ok(()) +} diff --git a/src/tools/cargo/crates/xtask-stale-label/Cargo.toml b/src/tools/cargo/crates/xtask-stale-label/Cargo.toml new file mode 100644 index 000000000..af3218e96 --- /dev/null +++ b/src/tools/cargo/crates/xtask-stale-label/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "xtask-stale-label" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies] +toml_edit.workspace = true diff --git a/src/tools/cargo/crates/xtask-stale-label/src/main.rs b/src/tools/cargo/crates/xtask-stale-label/src/main.rs new file mode 100644 index 000000000..37675979c --- /dev/null +++ b/src/tools/cargo/crates/xtask-stale-label/src/main.rs @@ -0,0 +1,91 @@ +//! ```text +//! NAME +//! stale-label +//! +//! SYNOPSIS +//! stale-label +//! +//! DESCRIPTION +//! Detect stale paths in autolabel definitions in triagebot.toml. +//! Probably autofix them in the future. +//! ``` + +use std::fmt::Write as _; +use std::path::PathBuf; +use std::process; +use toml_edit::Document; + +fn main() { + let pkg_root = std::env!("CARGO_MANIFEST_DIR"); + let ws_root = PathBuf::from(format!("{pkg_root}/../..")); + let path = { + let path = ws_root.join("triagebot.toml"); + path.canonicalize().unwrap_or(path) + }; + + eprintln!("Checking file {path:?}\n"); + + let mut failed = 0; + let mut passed = 0; + + let toml = std::fs::read_to_string(path).expect("read from file"); + let doc = toml.parse::<Document>().expect("a toml"); + let autolabel = doc["autolabel"].as_table().expect("a toml table"); + + for (label, value) in autolabel.iter() { + let Some(trigger_files) = value.get("trigger_files") else { + continue + }; + let trigger_files = trigger_files.as_array().expect("an array"); + let missing_files: Vec<_> = trigger_files + .iter() + // Hey TOML content is strict UTF-8. + .map(|v| v.as_str().unwrap()) + .filter(|f| { + // triagebot checks with `starts_with` only. + // See https://github.com/rust-lang/triagebot/blob/0e4b48ca86ffede9cc70fb1611e658e4d013bce2/src/handlers/autolabel.rs#L45 + let path = ws_root.join(f); + if path.exists() { + return false; + } + let Some(mut read_dir) = path.parent().and_then(|p| p.read_dir().ok()) else { + return true; + }; + !read_dir.any(|e| { + e.unwrap() + .path() + .strip_prefix(&ws_root) + .unwrap() + .to_str() + .unwrap() + .starts_with(f) + }) + }) + .collect(); + + failed += missing_files.len(); + passed += trigger_files.len() - missing_files.len(); + + if missing_files.is_empty() { + continue; + } + + let mut msg = String::new(); + writeln!( + &mut msg, + "missing files defined in `autolabel.{label}.trigger_files`:" + ) + .unwrap(); + for f in missing_files.iter() { + writeln!(&mut msg, "\t {f}").unwrap(); + } + eprintln!("{msg}"); + } + + let result = if failed == 0 { "ok" } else { "FAILED" }; + eprintln!("test result: {result}. {passed} passed; {failed} failed;"); + + if failed > 0 { + process::exit(1); + } +} diff --git a/src/tools/cargo/crates/xtask-unpublished/Cargo.toml b/src/tools/cargo/crates/xtask-unpublished/Cargo.toml new file mode 100644 index 000000000..541a34dea --- /dev/null +++ b/src/tools/cargo/crates/xtask-unpublished/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "xtask-unpublished" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies] +anyhow.workspace = true +cargo.workspace = true +clap.workspace = true +env_logger.workspace = true +log.workspace = true diff --git a/src/tools/cargo/crates/xtask-unpublished/src/main.rs b/src/tools/cargo/crates/xtask-unpublished/src/main.rs new file mode 100644 index 000000000..1942a3621 --- /dev/null +++ b/src/tools/cargo/crates/xtask-unpublished/src/main.rs @@ -0,0 +1,15 @@ +mod xtask; + +fn main() { + env_logger::init_from_env("CARGO_LOG"); + let cli = xtask::cli(); + let matches = cli.get_matches(); + + let mut config = cargo::util::config::Config::default().unwrap_or_else(|e| { + let mut eval = cargo::core::shell::Shell::new(); + cargo::exit_with_error(e.into(), &mut eval) + }); + if let Err(e) = xtask::exec(&matches, &mut config) { + cargo::exit_with_error(e, &mut config.shell()) + } +} diff --git a/src/tools/cargo/crates/xtask-unpublished/src/xtask.rs b/src/tools/cargo/crates/xtask-unpublished/src/xtask.rs new file mode 100644 index 000000000..f1086951f --- /dev/null +++ b/src/tools/cargo/crates/xtask-unpublished/src/xtask.rs @@ -0,0 +1,200 @@ +//! `xtask-unpublished` outputs a table with publish status --- a local version +//! and a version on crates.io for comparisons. +//! +//! This aims to help developers check if there is any crate required a new +//! publish, as well as detect if a version bump is needed in CI pipeline. + +use std::collections::HashSet; + +use cargo::core::registry::PackageRegistry; +use cargo::core::QueryKind; +use cargo::core::Registry; +use cargo::core::SourceId; +use cargo::ops::Packages; +use cargo::util::command_prelude::*; + +pub fn cli() -> clap::Command { + clap::Command::new("xtask-unpublished") + .arg_package_spec_simple("Package to inspect the published status") + .arg( + opt( + "verbose", + "Use verbose output (-vv very verbose/build.rs output)", + ) + .short('v') + .action(ArgAction::Count) + .global(true), + ) + .arg_quiet() + .arg( + opt("color", "Coloring: auto, always, never") + .value_name("WHEN") + .global(true), + ) + .arg(flag("frozen", "Require Cargo.lock and cache are up to date").global(true)) + .arg(flag("locked", "Require Cargo.lock is up to date").global(true)) + .arg(flag("offline", "Run without accessing the network").global(true)) + .arg(multi_opt("config", "KEY=VALUE", "Override a configuration value").global(true)) + .arg( + Arg::new("unstable-features") + .help("Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details") + .short('Z') + .value_name("FLAG") + .action(ArgAction::Append) + .global(true), + ) +} + +pub fn exec(args: &clap::ArgMatches, config: &mut cargo::util::Config) -> cargo::CliResult { + config_configure(config, args)?; + + unpublished(args, config)?; + + Ok(()) +} + +fn config_configure(config: &mut Config, args: &ArgMatches) -> CliResult { + let verbose = args.verbose(); + // quiet is unusual because it is redefined in some subcommands in order + // to provide custom help text. + let quiet = args.flag("quiet"); + let color = args.get_one::<String>("color").map(String::as_str); + let frozen = args.flag("frozen"); + let locked = args.flag("locked"); + let offline = args.flag("offline"); + let mut unstable_flags = vec![]; + if let Some(values) = args.get_many::<String>("unstable-features") { + unstable_flags.extend(values.cloned()); + } + let mut config_args = vec![]; + if let Some(values) = args.get_many::<String>("config") { + config_args.extend(values.cloned()); + } + config.configure( + verbose, + quiet, + color, + frozen, + locked, + offline, + &None, + &unstable_flags, + &config_args, + )?; + Ok(()) +} + +fn unpublished(args: &clap::ArgMatches, config: &mut cargo::util::Config) -> cargo::CliResult { + let ws = args.workspace(config)?; + + let members_to_inspect: HashSet<_> = { + let pkgs = args.packages_from_flags()?; + if let Packages::Packages(_) = pkgs { + HashSet::from_iter(pkgs.get_packages(&ws)?) + } else { + HashSet::from_iter(ws.members()) + } + }; + + let mut results = Vec::new(); + { + let mut registry = PackageRegistry::new(config)?; + let _lock = config.acquire_package_cache_lock()?; + registry.lock_patches(); + let source_id = SourceId::crates_io(config)?; + + for member in members_to_inspect { + let name = member.name(); + let current = member.version(); + if member.publish() == &Some(vec![]) { + log::trace!("skipping {name}, `publish = false`"); + continue; + } + + let version_req = format!("<={current}"); + let query = + cargo::core::dependency::Dependency::parse(name, Some(&version_req), source_id)?; + let possibilities = loop { + // Exact to avoid returning all for path/git + match registry.query_vec(&query, QueryKind::Exact) { + std::task::Poll::Ready(res) => { + break res?; + } + std::task::Poll::Pending => registry.block_until_ready()?, + } + }; + let (last, published) = possibilities + .iter() + .map(|s| s.version()) + .max() + .map(|last| (last.to_string(), last == current)) + .unwrap_or(("-".to_string(), false)); + + results.push(vec![ + name.to_string(), + last, + current.to_string(), + if published { "yes" } else { "no" }.to_string(), + ]); + } + } + results.sort(); + + if results.is_empty() { + return Ok(()); + } + + results.insert( + 0, + vec![ + "name".to_owned(), + "crates.io".to_owned(), + "local".to_owned(), + "published?".to_owned(), + ], + ); + + output_table(results); + + Ok(()) +} + +/// Outputs a markdown table like this. +/// +/// ```text +/// | name | crates.io | local | published? | +/// |------------------|-----------|--------|------------| +/// | cargo | 0.70.1 | 0.72.0 | no | +/// | cargo-platform | 0.1.2 | 0.1.2 | yes | +/// | cargo-util | - | 0.2.4 | no | +/// | crates-io | 0.36.0 | 0.36.0 | yes | +/// | home | - | 0.5.6 | no | +/// ``` +fn output_table(table: Vec<Vec<String>>) { + let header = table.first().unwrap(); + let paddings = table.iter().fold(vec![0; header.len()], |mut widths, row| { + for (width, field) in widths.iter_mut().zip(row) { + *width = usize::max(*width, field.len()); + } + widths + }); + + let print = |row: &[_]| { + for (field, pad) in row.iter().zip(&paddings) { + print!("| {field:pad$} "); + } + println!("|"); + }; + + print(header); + + paddings.iter().for_each(|fill| print!("|-{:-<fill$}-", "")); + println!("|"); + + table.iter().skip(1).for_each(|r| print(r)); +} + +#[test] +fn verify_cli() { + cli().debug_assert(); +} diff --git a/src/tools/cargo/crates/credential/README.md b/src/tools/cargo/credential/README.md index 168cc71c3..168cc71c3 100644 --- a/src/tools/cargo/crates/credential/README.md +++ b/src/tools/cargo/credential/README.md diff --git a/src/tools/cargo/crates/credential/cargo-credential-1password/Cargo.toml b/src/tools/cargo/credential/cargo-credential-1password/Cargo.toml index 093fde8e5..8db40e577 100644 --- a/src/tools/cargo/crates/credential/cargo-credential-1password/Cargo.toml +++ b/src/tools/cargo/credential/cargo-credential-1password/Cargo.toml @@ -7,6 +7,6 @@ repository = "https://github.com/rust-lang/cargo" description = "A Cargo credential process that stores tokens in a 1password vault." [dependencies] -cargo-credential = { version = "0.2.0", path = "../cargo-credential" } -serde = { version = "1.0.117", features = ["derive"] } -serde_json = "1.0.59" +cargo-credential.workspace = true +serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true diff --git a/src/tools/cargo/crates/credential/cargo-credential-1password/src/main.rs b/src/tools/cargo/credential/cargo-credential-1password/src/main.rs index 4f512b717..4f512b717 100644 --- a/src/tools/cargo/crates/credential/cargo-credential-1password/src/main.rs +++ b/src/tools/cargo/credential/cargo-credential-1password/src/main.rs diff --git a/src/tools/cargo/crates/credential/cargo-credential-gnome-secret/Cargo.toml b/src/tools/cargo/credential/cargo-credential-gnome-secret/Cargo.toml index 12e25cfb6..63b3e95cc 100644 --- a/src/tools/cargo/crates/credential/cargo-credential-gnome-secret/Cargo.toml +++ b/src/tools/cargo/credential/cargo-credential-gnome-secret/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/rust-lang/cargo" description = "A Cargo credential process that stores tokens with GNOME libsecret." [dependencies] -cargo-credential = { version = "0.2.0", path = "../cargo-credential" } +cargo-credential.workspace = true [build-dependencies] -pkg-config = "0.3.19" +pkg-config.workspace = true diff --git a/src/tools/cargo/crates/credential/cargo-credential-gnome-secret/build.rs b/src/tools/cargo/credential/cargo-credential-gnome-secret/build.rs index 9283535af..9283535af 100644 --- a/src/tools/cargo/crates/credential/cargo-credential-gnome-secret/build.rs +++ b/src/tools/cargo/credential/cargo-credential-gnome-secret/build.rs diff --git a/src/tools/cargo/crates/credential/cargo-credential-gnome-secret/src/main.rs b/src/tools/cargo/credential/cargo-credential-gnome-secret/src/main.rs index 40972b05d..40972b05d 100644 --- a/src/tools/cargo/crates/credential/cargo-credential-gnome-secret/src/main.rs +++ b/src/tools/cargo/credential/cargo-credential-gnome-secret/src/main.rs diff --git a/src/tools/cargo/crates/credential/cargo-credential-macos-keychain/Cargo.toml b/src/tools/cargo/credential/cargo-credential-macos-keychain/Cargo.toml index c2c22a425..6311b71de 100644 --- a/src/tools/cargo/crates/credential/cargo-credential-macos-keychain/Cargo.toml +++ b/src/tools/cargo/credential/cargo-credential-macos-keychain/Cargo.toml @@ -7,5 +7,7 @@ repository = "https://github.com/rust-lang/cargo" description = "A Cargo credential process that stores tokens in a macOS keychain." [dependencies] -cargo-credential = { version = "0.2.0", path = "../cargo-credential" } -security-framework = "2.0.0" +cargo-credential.workspace = true + +[target.'cfg(target_os = "macos")'.dependencies] +security-framework.workspace = true diff --git a/src/tools/cargo/credential/cargo-credential-macos-keychain/src/main.rs b/src/tools/cargo/credential/cargo-credential-macos-keychain/src/main.rs new file mode 100644 index 000000000..4d6ea96d0 --- /dev/null +++ b/src/tools/cargo/credential/cargo-credential-macos-keychain/src/main.rs @@ -0,0 +1,58 @@ +//! Cargo registry macos keychain credential process. + +#[cfg(target_os = "macos")] +mod macos { + use cargo_credential::{Credential, Error}; + use security_framework::os::macos::keychain::SecKeychain; + + pub(crate) struct MacKeychain; + + /// The account name is not used. + const ACCOUNT: &'static str = ""; + + fn registry(registry_name: &str) -> String { + format!("cargo-registry:{}", registry_name) + } + + impl Credential for MacKeychain { + fn name(&self) -> &'static str { + env!("CARGO_PKG_NAME") + } + + fn get(&self, index_url: &str) -> Result<String, Error> { + let keychain = SecKeychain::default().unwrap(); + let service_name = registry(index_url); + let (pass, _item) = keychain.find_generic_password(&service_name, ACCOUNT)?; + String::from_utf8(pass.as_ref().to_vec()) + .map_err(|_| "failed to convert token to UTF8".into()) + } + + fn store(&self, index_url: &str, token: &str, name: Option<&str>) -> Result<(), Error> { + let keychain = SecKeychain::default().unwrap(); + let service_name = registry(name.unwrap_or(index_url)); + if let Ok((_pass, mut item)) = keychain.find_generic_password(&service_name, ACCOUNT) { + item.set_password(token.as_bytes())?; + } else { + keychain.add_generic_password(&service_name, ACCOUNT, token.as_bytes())?; + } + Ok(()) + } + + fn erase(&self, index_url: &str) -> Result<(), Error> { + let keychain = SecKeychain::default().unwrap(); + let service_name = registry(index_url); + let (_pass, item) = keychain.find_generic_password(&service_name, ACCOUNT)?; + item.delete(); + Ok(()) + } + } +} + +#[cfg(not(target_os = "macos"))] +use cargo_credential::UnsupportedCredential as MacKeychain; +#[cfg(target_os = "macos")] +use macos::MacKeychain; + +fn main() { + cargo_credential::main(MacKeychain); +} diff --git a/src/tools/cargo/crates/credential/cargo-credential-wincred/Cargo.toml b/src/tools/cargo/credential/cargo-credential-wincred/Cargo.toml index 83c38e80d..cd168a8a3 100644 --- a/src/tools/cargo/crates/credential/cargo-credential-wincred/Cargo.toml +++ b/src/tools/cargo/credential/cargo-credential-wincred/Cargo.toml @@ -7,5 +7,8 @@ repository = "https://github.com/rust-lang/cargo" description = "A Cargo credential process that stores tokens with Windows Credential Manager." [dependencies] -cargo-credential = { version = "0.2.0", path = "../cargo-credential" } -windows-sys = { version = "0.45", features = ["Win32_Foundation", "Win32_Security_Credentials"] } +cargo-credential.workspace = true + +[target.'cfg(windows)'.dependencies.windows-sys] +features = ["Win32_Foundation", "Win32_Security_Credentials"] +workspace = true diff --git a/src/tools/cargo/credential/cargo-credential-wincred/src/main.rs b/src/tools/cargo/credential/cargo-credential-wincred/src/main.rs new file mode 100644 index 000000000..4377172e8 --- /dev/null +++ b/src/tools/cargo/credential/cargo-credential-wincred/src/main.rs @@ -0,0 +1,122 @@ +//! Cargo registry windows credential process. + +#[cfg(windows)] +mod win { + use cargo_credential::{Credential, Error}; + use std::ffi::OsStr; + use std::os::windows::ffi::OsStrExt; + + use windows_sys::core::PWSTR; + use windows_sys::Win32::Foundation::ERROR_NOT_FOUND; + use windows_sys::Win32::Foundation::FILETIME; + use windows_sys::Win32::Foundation::TRUE; + use windows_sys::Win32::Security::Credentials::CredDeleteW; + use windows_sys::Win32::Security::Credentials::CredReadW; + use windows_sys::Win32::Security::Credentials::CredWriteW; + use windows_sys::Win32::Security::Credentials::CREDENTIALW; + use windows_sys::Win32::Security::Credentials::CRED_PERSIST_LOCAL_MACHINE; + use windows_sys::Win32::Security::Credentials::CRED_TYPE_GENERIC; + + pub(crate) struct WindowsCredential; + + /// Converts a string to a nul-terminated wide UTF-16 byte sequence. + fn wstr(s: &str) -> Vec<u16> { + let mut wide: Vec<u16> = OsStr::new(s).encode_wide().collect(); + if wide.iter().any(|b| *b == 0) { + panic!("nul byte in wide string"); + } + wide.push(0); + wide + } + + fn target_name(registry_name: &str) -> Vec<u16> { + wstr(&format!("cargo-registry:{}", registry_name)) + } + + impl Credential for WindowsCredential { + fn name(&self) -> &'static str { + env!("CARGO_PKG_NAME") + } + + fn get(&self, index_url: &str) -> Result<String, Error> { + let target_name = target_name(index_url); + let p_credential: *mut CREDENTIALW = std::ptr::null_mut() as *mut _; + unsafe { + if CredReadW( + target_name.as_ptr(), + CRED_TYPE_GENERIC, + 0, + p_credential as *mut _ as *mut _, + ) != TRUE + { + return Err(format!( + "failed to fetch token: {}", + std::io::Error::last_os_error() + ) + .into()); + } + let bytes = std::slice::from_raw_parts( + (*p_credential).CredentialBlob, + (*p_credential).CredentialBlobSize as usize, + ); + String::from_utf8(bytes.to_vec()) + .map_err(|_| "failed to convert token to UTF8".into()) + } + } + + fn store(&self, index_url: &str, token: &str, name: Option<&str>) -> Result<(), Error> { + let token = token.as_bytes(); + let target_name = target_name(index_url); + let comment = match name { + Some(name) => wstr(&format!("Cargo registry token for {}", name)), + None => wstr("Cargo registry token"), + }; + let mut credential = CREDENTIALW { + Flags: 0, + Type: CRED_TYPE_GENERIC, + TargetName: target_name.as_ptr() as PWSTR, + Comment: comment.as_ptr() as PWSTR, + LastWritten: FILETIME { + dwLowDateTime: 0, + dwHighDateTime: 0, + }, + CredentialBlobSize: token.len() as u32, + CredentialBlob: token.as_ptr() as *mut u8, + Persist: CRED_PERSIST_LOCAL_MACHINE, + AttributeCount: 0, + Attributes: std::ptr::null_mut(), + TargetAlias: std::ptr::null_mut(), + UserName: std::ptr::null_mut(), + }; + let result = unsafe { CredWriteW(&mut credential, 0) }; + if result != TRUE { + let err = std::io::Error::last_os_error(); + return Err(format!("failed to store token: {}", err).into()); + } + Ok(()) + } + + fn erase(&self, index_url: &str) -> Result<(), Error> { + let target_name = target_name(index_url); + let result = unsafe { CredDeleteW(target_name.as_ptr(), CRED_TYPE_GENERIC, 0) }; + if result != TRUE { + let err = std::io::Error::last_os_error(); + if err.raw_os_error() == Some(ERROR_NOT_FOUND as i32) { + eprintln!("not currently logged in to `{}`", index_url); + return Ok(()); + } + return Err(format!("failed to remove token: {}", err).into()); + } + Ok(()) + } + } +} + +#[cfg(not(windows))] +use cargo_credential::UnsupportedCredential as WindowsCredential; +#[cfg(windows)] +use win::WindowsCredential; + +fn main() { + cargo_credential::main(WindowsCredential); +} diff --git a/src/tools/cargo/crates/credential/cargo-credential/Cargo.toml b/src/tools/cargo/credential/cargo-credential/Cargo.toml index 2addaf5af..2addaf5af 100644 --- a/src/tools/cargo/crates/credential/cargo-credential/Cargo.toml +++ b/src/tools/cargo/credential/cargo-credential/Cargo.toml diff --git a/src/tools/cargo/crates/credential/cargo-credential/README.md b/src/tools/cargo/credential/cargo-credential/README.md index 1f75e598a..53dc8e6b7 100644 --- a/src/tools/cargo/crates/credential/cargo-credential/README.md +++ b/src/tools/cargo/credential/cargo-credential/README.md @@ -8,7 +8,7 @@ Documentation about credential processes may be found at https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process Example implementations may be found at -https://github.com/rust-lang/cargo/tree/master/crates/credential +https://github.com/rust-lang/cargo/tree/master/credential ## Usage diff --git a/src/tools/cargo/crates/credential/cargo-credential/src/lib.rs b/src/tools/cargo/credential/cargo-credential/src/lib.rs index 3baf42d77..c75172242 100644 --- a/src/tools/cargo/crates/credential/cargo-credential/src/lib.rs +++ b/src/tools/cargo/credential/cargo-credential/src/lib.rs @@ -34,6 +34,26 @@ pub trait Credential { fn erase(&self, index_url: &str) -> Result<(), Error>; } +pub struct UnsupportedCredential; + +impl Credential for UnsupportedCredential { + fn name(&self) -> &'static str { + "unsupported" + } + + fn get(&self, _index_url: &str) -> Result<String, Error> { + Err("unsupported".into()) + } + + fn store(&self, _index_url: &str, _token: &str, _name: Option<&str>) -> Result<(), Error> { + Err("unsupported".into()) + } + + fn erase(&self, _index_url: &str) -> Result<(), Error> { + Err("unsupported".into()) + } +} + /// Runs the credential interaction by processing the command-line and /// environment variables. pub fn main(credential: impl Credential) { diff --git a/src/tools/cargo/src/bin/cargo/cli.rs b/src/tools/cargo/src/bin/cargo/cli.rs index 17120a656..946816571 100644 --- a/src/tools/cargo/src/bin/cargo/cli.rs +++ b/src/tools/cargo/src/bin/cargo/cli.rs @@ -440,6 +440,9 @@ pub fn cli() -> Command { "cargo [OPTIONS] [COMMAND]" }; Command::new("cargo") + // Subcommands all count their args' display order independently (from 0), + // which makes their args interspersed with global args. This puts global args last. + .next_display_order(1000) .allow_external_subcommands(true) // Doesn't mix well with our list of common cargo commands. See clap-rs/clap#3108 for // opening clap up to allow us to style our help template diff --git a/src/tools/cargo/src/bin/cargo/commands/add.rs b/src/tools/cargo/src/bin/cargo/commands/add.rs index 39f0e189e..90c4f4dd5 100644 --- a/src/tools/cargo/src/bin/cargo/commands/add.rs +++ b/src/tools/cargo/src/bin/cargo/commands/add.rs @@ -72,6 +72,10 @@ The package will be removed from your features.") Example uses: - Depending on multiple versions of a crate - Depend on crates with the same name from different registries"), + flag( + "ignore-rust-version", + "Ignore `rust-version` specification in packages (unstable)" + ), ]) .arg_manifest_path() .arg_package("Package to modify") @@ -188,12 +192,24 @@ pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let dependencies = parse_dependencies(config, args)?; + let ignore_rust_version = args.flag("ignore-rust-version"); + if ignore_rust_version && !config.cli_unstable().msrv_policy { + return Err(CliError::new( + anyhow::format_err!( + "`--ignore-rust-version` is unstable; pass `-Zmsrv-policy` to enable support for it" + ), + 101, + )); + } + let honor_rust_version = !ignore_rust_version; + let options = AddOptions { config, spec, dependencies, section, dry_run, + honor_rust_version, }; add(&ws, &options)?; diff --git a/src/tools/cargo/src/bin/cargo/main.rs b/src/tools/cargo/src/bin/cargo/main.rs index 55da2997f..9fb6635ea 100644 --- a/src/tools/cargo/src/bin/cargo/main.rs +++ b/src/tools/cargo/src/bin/cargo/main.rs @@ -293,10 +293,6 @@ fn init_git(config: &Config) { /// configured to use libcurl instead of the built-in networking support so /// that those configuration settings can be used. fn init_git_transports(config: &Config) { - // Only use a custom transport if any HTTP options are specified, - // such as proxies or custom certificate authorities. The custom - // transport, however, is not as well battle-tested. - match cargo::ops::needs_custom_http_transport(config) { Ok(true) => {} _ => return, diff --git a/src/tools/cargo/src/cargo/core/compiler/build_context/target_info.rs b/src/tools/cargo/src/cargo/core/compiler/build_context/target_info.rs index bf8bb1578..e6e41c522 100644 --- a/src/tools/cargo/src/cargo/core/compiler/build_context/target_info.rs +++ b/src/tools/cargo/src/cargo/core/compiler/build_context/target_info.rs @@ -7,6 +7,7 @@ //! * [`RustcTargetData::info`] to get a [`TargetInfo`] for an in-depth query. //! * [`TargetInfo::rustc_outputs`] to get a list of supported file types. +use crate::core::compiler::apply_env_config; use crate::core::compiler::{ BuildOutput, CompileKind, CompileMode, CompileTarget, Context, CrateType, }; @@ -38,7 +39,7 @@ pub struct TargetInfo { /// /// The key is the crate type name (like `cdylib`) and the value is /// `Some((prefix, suffix))`, for example `libcargo.so` would be - /// `Some(("lib", ".so")). The value is `None` if the crate type is not + /// `Some(("lib", ".so"))`. The value is `None` if the crate type is not /// supported. crate_types: RefCell<HashMap<CrateType, Option<(String, String)>>>, /// `cfg` information extracted from `rustc --print=cfg`. @@ -175,6 +176,7 @@ impl TargetInfo { // // Search `--print` to see what we query so far. let mut process = rustc.workspace_process(); + apply_env_config(config, &mut process)?; process .arg("-") .arg("--crate-name") diff --git a/src/tools/cargo/src/cargo/core/compiler/compilation.rs b/src/tools/cargo/src/cargo/core/compiler/compilation.rs index 29642f13d..b263119b0 100644 --- a/src/tools/cargo/src/cargo/core/compiler/compilation.rs +++ b/src/tools/cargo/src/cargo/core/compiler/compilation.rs @@ -7,7 +7,8 @@ use std::path::PathBuf; use cargo_platform::CfgExpr; use cargo_util::{paths, ProcessBuilder}; -use super::BuildContext; +use crate::core::compiler::apply_env_config; +use crate::core::compiler::BuildContext; use crate::core::compiler::{CompileKind, Metadata, Unit}; use crate::core::Package; use crate::util::{config, CargoResult, Config}; @@ -349,17 +350,7 @@ impl<'cfg> Compilation<'cfg> { ) .cwd(pkg.root()); - // 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() || self.config.get_env_os(key).is_none() { - cmd.env(key, value.resolve(self.config)); - } - } + apply_env_config(self.config, &mut cmd)?; Ok(cmd) } diff --git a/src/tools/cargo/src/cargo/core/compiler/custom_build.rs b/src/tools/cargo/src/cargo/core/compiler/custom_build.rs index 5728d0c85..01890e542 100644 --- a/src/tools/cargo/src/cargo/core/compiler/custom_build.rs +++ b/src/tools/cargo/src/cargo/core/compiler/custom_build.rs @@ -1,3 +1,36 @@ +//! How to execute a build script and parse its output. +//! +//! ## Preparing a build script run +//! +//! A [build script] is an optional Rust script Cargo will run before building +//! your package. As of this writing, two kinds of special [`Unit`]s will be +//! constructed when there is a build script in a package. +//! +//! * Build script compilation --- This unit is generally the same as units +//! that would compile other Cargo targets. It will recursively creates units +//! of its dependencies. One biggest difference is that the [`Unit`] of +//! compiling a build script is flagged as [`TargetKind::CustomBuild`]. +//! * Build script executaion --- During the construction of the [`UnitGraph`], +//! Cargo inserts a [`Unit`] with [`CompileMode::RunCustomBuild`]. This unit +//! depends on the unit of compiling the associated build script, to ensure +//! the executable is available before running. The [`Work`] of running the +//! build script is prepared in the function [`prepare`]. +//! +//! ## Running a build script +//! +//! When running a build script, Cargo is aware of the progress and the result +//! of a build script. Standard output is the chosen interprocess communication +//! between Cargo and build script processes. A set of strings is defined for +//! that purpose. These strings, a.k.a. instructions, are interpreted by +//! [`BuildOutput::parse`] and stored in [`Context::build_script_outputs`]. +//! The entire execution work is constructed by [`build_work`]. +//! +//! [build script]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html +//! [`TargetKind::CustomBuild`]: crate::core::manifest::TargetKind::CustomBuild +//! [`UnitGraph`]: super::unit_graph::UnitGraph +//! [`CompileMode::RunCustomBuild`]: super::CompileMode +//! [instructions]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script + use super::{fingerprint, Context, Job, LinkType, Unit, Work}; use crate::core::compiler::artifact; use crate::core::compiler::context::Metadata; @@ -15,6 +48,10 @@ use std::path::{Path, PathBuf}; use std::str; use std::sync::{Arc, Mutex}; +/// A build script instruction that tells Cargo to display a warning after the +/// build script has finished running. Read [the doc] for more. +/// +/// [the doc]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#cargo-warning const CARGO_WARNING: &str = "cargo:warning="; /// Contains the parsed output of a custom build script. @@ -63,7 +100,7 @@ pub struct BuildScriptOutputs { /// Linking information for a `Unit`. /// -/// See `build_map` for more details. +/// See [`build_map`] for more details. #[derive(Default)] pub struct BuildScripts { /// List of build script outputs this Unit needs to include for linking. Each @@ -96,7 +133,8 @@ pub struct BuildScripts { pub plugins: BTreeSet<(PackageId, Metadata)>, } -/// Dependency information as declared by a build script. +/// Dependency information as declared by a build script that might trigger +/// a recompile of itself. #[derive(Debug)] pub struct BuildDeps { /// Absolute path to the file in the target directory that stores the @@ -130,6 +168,8 @@ pub fn prepare(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Job> { } } +/// Emits the output of a build script as a [`machine_message::BuildScript`] +/// JSON string to standard output. fn emit_build_output( state: &JobState<'_, '_>, output: &BuildOutput, @@ -155,6 +195,14 @@ fn emit_build_output( Ok(()) } +/// Constructs the unit of work of running a build script. +/// +/// The construction includes: +/// +/// * Set environment varibles for the build script run. +/// * Create the output dir (`OUT_DIR`) for the build script output. +/// * Determine if the build script needs a re-run. +/// * Run the build script and store its output. fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Job> { assert!(unit.mode.is_run_custom_build()); let bcx = &cx.bcx; @@ -517,6 +565,8 @@ fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Job> { Ok(job) } +/// When a build script run fails, store only warnings and nuke other outputs, +/// as they are likely broken. fn insert_warnings_in_build_outputs( build_script_outputs: Arc<Mutex<BuildScriptOutputs>>, id: PackageId, @@ -534,6 +584,7 @@ fn insert_warnings_in_build_outputs( } impl BuildOutput { + /// Like [`BuildOutput::parse`] but from a file path. pub fn parse_file( path: &Path, library_name: Option<String>, @@ -557,9 +608,13 @@ impl BuildOutput { ) } - // Parses the output of a script. - // The `pkg_descr` is used for error messages. - // The `library_name` is used for determining if RUSTC_BOOTSTRAP should be allowed. + /// Parses the output instructions of a build script. + /// + /// * `pkg_descr` --- for error messages + /// * `library_name` --- for determining if `RUSTC_BOOTSTRAP` should be allowed + /// * `extra_check_cfg` --- for unstable feature [`-Zcheck-cfg`] + /// + /// [`-Zcheck-cfg`]: https://doc.rust-lang.org/cargo/reference/unstable.html#check-cfg pub fn parse( input: &[u8], // Takes String instead of InternedString so passing `unit.pkg.name()` will give a compile error. @@ -781,6 +836,9 @@ impl BuildOutput { }) } + /// Parses [`cargo:rustc-flags`] instruction. + /// + /// [`cargo:rustc-flags`]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#cargorustc-flagsflags pub fn parse_rustc_flags( value: &str, whence: &str, @@ -826,6 +884,9 @@ impl BuildOutput { Ok((library_paths, library_links)) } + /// Parses [`cargo:rustc-env`] instruction. + /// + /// [`cargo:rustc-env`]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-env pub fn parse_rustc_env(value: &str, whence: &str) -> CargoResult<(String, String)> { let mut iter = value.splitn(2, '='); let name = iter.next(); @@ -837,6 +898,9 @@ impl BuildOutput { } } +/// Prepares the Rust script for the unstable feature [metabuild]. +/// +/// [metabuild]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#metabuild fn prepare_metabuild(cx: &Context<'_, '_>, unit: &Unit, deps: &[String]) -> CargoResult<()> { let mut output = Vec::new(); let available_deps = cx.unit_deps(unit); @@ -866,6 +930,8 @@ fn prepare_metabuild(cx: &Context<'_, '_>, unit: &Unit, deps: &[String]) -> Carg } impl BuildDeps { + /// Creates a build script dependency information from a previous + /// build script output path and the content. pub fn new(output_file: &Path, output: Option<&BuildOutput>) -> BuildDeps { BuildDeps { build_script_output: output_file.to_path_buf(), @@ -881,22 +947,27 @@ impl BuildDeps { } } -/// Computes several maps in `Context`: -/// - `build_scripts`: A map that tracks which build scripts each package +/// Computes several maps in [`Context`]. +/// +/// - [`build_scripts`]: A map that tracks which build scripts each package /// depends on. -/// - `build_explicit_deps`: Dependency statements emitted by build scripts +/// - [`build_explicit_deps`]: Dependency statements emitted by build scripts /// from a previous run. -/// - `build_script_outputs`: Pre-populates this with any overridden build +/// - [`build_script_outputs`]: Pre-populates this with any overridden build /// scripts. /// -/// The important one here is `build_scripts`, which for each `(package, -/// metadata)` stores a `BuildScripts` object which contains a list of -/// dependencies with build scripts that the unit should consider when -/// linking. For example this lists all dependencies' `-L` flags which need to -/// be propagated transitively. +/// The important one here is [`build_scripts`], which for each `(package, +/// metadata)` stores a [`BuildScripts`] object which contains a list of +/// dependencies with build scripts that the unit should consider when linking. +/// For example this lists all dependencies' `-L` flags which need to be +/// propagated transitively. /// /// The given set of units to this function is the initial set of /// targets/profiles which are being built. +/// +/// [`build_scripts`]: Context::build_scripts +/// [`build_explicit_deps`]: Context::build_explicit_deps +/// [`build_script_outputs`]: Context::build_script_outputs pub fn build_map(cx: &mut Context<'_, '_>) -> CargoResult<()> { let mut ret = HashMap::new(); for unit in &cx.bcx.roots { @@ -943,7 +1014,6 @@ pub fn build_map(cx: &mut Context<'_, '_>) -> CargoResult<()> { add_to_link(&mut ret, unit.pkg.package_id(), script_meta); } - // Load any dependency declarations from a previous run. if unit.mode.is_run_custom_build() { parse_previous_explicit_deps(cx, unit); } @@ -982,6 +1052,7 @@ pub fn build_map(cx: &mut Context<'_, '_>) -> CargoResult<()> { } } + /// Load any dependency declarations from a previous build script run. fn parse_previous_explicit_deps(cx: &mut Context<'_, '_>, unit: &Unit) { let script_run_dir = cx.files().build_script_run_dir(unit); let output_file = script_run_dir.join("output"); diff --git a/src/tools/cargo/src/cargo/core/compiler/fingerprint/mod.rs b/src/tools/cargo/src/cargo/core/compiler/fingerprint/mod.rs index 7401afebc..a3523110b 100644 --- a/src/tools/cargo/src/cargo/core/compiler/fingerprint/mod.rs +++ b/src/tools/cargo/src/cargo/core/compiler/fingerprint/mod.rs @@ -75,6 +75,7 @@ //! [`Lto`] flags | ✓ | ✓ //! config settings[^5] | ✓ | //! is_std | | ✓ +//! `[lints]` table[^6] | ✓ | //! //! [^1]: Build script and bin dependencies are not included. //! @@ -86,6 +87,8 @@ //! [^5]: Config settings that are not otherwise captured anywhere else. //! Currently, this is only `doc.extern-map`. //! +//! [^6]: Via [`Manifest::lint_rustflags`][crate::core::Manifest::lint_rustflags] +//! //! When deciding what should go in the Metadata vs the Fingerprint, consider //! that some files (like dylibs) do not have a hash in their filename. Thus, //! if a value changes, only the fingerprint will detect the change (consider, @@ -1414,6 +1417,7 @@ fn calculate_normal(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Finger unit.mode, cx.bcx.extra_args_for(unit), cx.lto[unit], + unit.pkg.manifest().lint_rustflags(), )); // Include metadata since it is exposed as environment variables. let m = unit.pkg.manifest().metadata(); diff --git a/src/tools/cargo/src/cargo/core/compiler/job_queue/mod.rs b/src/tools/cargo/src/cargo/core/compiler/job_queue/mod.rs index 38ab0fe49..6e8866b2b 100644 --- a/src/tools/cargo/src/cargo/core/compiler/job_queue/mod.rs +++ b/src/tools/cargo/src/cargo/core/compiler/job_queue/mod.rs @@ -487,7 +487,7 @@ impl<'cfg> JobQueue<'cfg> { timings: self.timings, tokens: Vec::new(), pending_queue: Vec::new(), - print: DiagnosticPrinter::new(cx.bcx.config), + print: DiagnosticPrinter::new(cx.bcx.config, &cx.bcx.rustc().workspace_wrapper), finished: 0, per_package_future_incompat_reports: Vec::new(), }; @@ -812,7 +812,7 @@ impl<'cfg> DrainState<'cfg> { ); if !cx.bcx.build_config.build_plan { // It doesn't really matter if this fails. - drop(cx.bcx.config.shell().status("Finished", message)); + let _ = cx.bcx.config.shell().status("Finished", message); future_incompat::save_and_display_report( cx.bcx, &self.per_package_future_incompat_reports, @@ -836,7 +836,7 @@ impl<'cfg> DrainState<'cfg> { if new_err.print_always || err_state.count == 0 { crate::display_error(&new_err.error, shell); if err_state.count == 0 && !self.active.is_empty() { - drop(shell.warn("build failed, waiting for other jobs to finish...")); + let _ = shell.warn("build failed, waiting for other jobs to finish..."); } err_state.count += 1; } else { @@ -863,11 +863,11 @@ impl<'cfg> DrainState<'cfg> { .values() .map(|u| self.name_for_progress(u)) .collect::<Vec<_>>(); - drop(self.progress.tick_now( + let _ = self.progress.tick_now( self.finished, self.total_units, &format!(": {}", active_names.join(", ")), - )); + ); } fn name_for_progress(&self, unit: &Unit) -> String { @@ -1005,12 +1005,16 @@ impl<'cfg> DrainState<'cfg> { message.push_str(" generated "); match count.total { 1 => message.push_str("1 warning"), - n => drop(write!(message, "{} warnings", n)), + n => { + let _ = write!(message, "{} warnings", n); + } }; match count.duplicates { 0 => {} 1 => message.push_str(" (1 duplicate)"), - n => drop(write!(message, " ({} duplicates)", n)), + n => { + let _ = write!(message, " ({} duplicates)", n); + } } // Only show the `cargo fix` message if its a local `Unit` if unit.is_local() { @@ -1045,16 +1049,16 @@ impl<'cfg> DrainState<'cfg> { if fixable > 1 { suggestions.push_str("s") } - drop(write!( + let _ = write!( message, " (run `{command} --{args}` to apply {suggestions})" - )) + ); } } } // Errors are ignored here because it is tricky to handle them // correctly, and they aren't important. - drop(config.shell().warn(message)); + let _ = config.shell().warn(message); } fn finish( diff --git a/src/tools/cargo/src/cargo/core/compiler/mod.rs b/src/tools/cargo/src/cargo/core/compiler/mod.rs index 7b43fd27d..7e49f0079 100644 --- a/src/tools/cargo/src/cargo/core/compiler/mod.rs +++ b/src/tools/cargo/src/cargo/core/compiler/mod.rs @@ -92,6 +92,7 @@ use crate::core::{Feature, PackageId, Target, Verbosity}; use crate::util::errors::{CargoResult, VerboseError}; use crate::util::interning::InternedString; use crate::util::machine_message::{self, Message}; +use crate::util::toml::TomlDebugInfo; use crate::util::{add_path_args, internal, iter_join_onto, profile}; use cargo_util::{paths, ProcessBuilder, ProcessError}; use rustfix::diagnostics::Applicability; @@ -603,9 +604,20 @@ fn link_targets(cx: &mut Context<'_, '_>, unit: &Unit, fresh: bool) -> CargoResu } if json_messages { + let debuginfo = profile.debuginfo.to_option().map(|d| match d { + TomlDebugInfo::None => machine_message::ArtifactDebuginfo::Int(0), + TomlDebugInfo::Limited => machine_message::ArtifactDebuginfo::Int(1), + TomlDebugInfo::Full => machine_message::ArtifactDebuginfo::Int(2), + TomlDebugInfo::LineDirectivesOnly => { + machine_message::ArtifactDebuginfo::Named("line-directives-only") + } + TomlDebugInfo::LineTablesOnly => { + machine_message::ArtifactDebuginfo::Named("line-tables-only") + } + }); let art_profile = machine_message::ArtifactProfile { opt_level: profile.opt_level.as_str(), - debuginfo: profile.debuginfo.to_option(), + debuginfo, debug_assertions: profile.debug_assertions, overflow_checks: profile.overflow_checks, test: unit_mode.is_any_test(), @@ -750,6 +762,7 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> { add_error_format_and_color(cx, &mut rustdoc); add_allow_features(cx, &mut rustdoc); + rustdoc.args(unit.pkg.manifest().lint_rustflags()); if let Some(args) = cx.bcx.extra_args_for(unit) { rustdoc.args(args); } @@ -1028,10 +1041,6 @@ fn build_base_args( cmd.arg("-C").arg(&format!("opt-level={}", opt_level)); } - if !rustflags.is_empty() { - cmd.args(&rustflags); - } - if *panic != PanicStrategy::Unwind { cmd.arg("-C").arg(format!("panic={}", panic)); } @@ -1066,6 +1075,10 @@ fn build_base_args( cmd.arg("-C").arg(format!("debuginfo={}", debuginfo)); } + cmd.args(unit.pkg.manifest().lint_rustflags()); + if !rustflags.is_empty() { + cmd.args(&rustflags); + } if let Some(args) = cx.bcx.extra_args_for(unit) { cmd.args(args); } @@ -1793,3 +1806,18 @@ fn descriptive_pkg_name(name: &str, target: &Target, mode: &CompileMode) -> Stri }; format!("`{name}` ({desc_name}{mode})") } + +/// Applies environment variables from config `[env]` to [`ProcessBuilder`]. +fn apply_env_config(config: &crate::Config, cmd: &mut ProcessBuilder) -> CargoResult<()> { + for (key, value) in 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() || config.get_env_os(key).is_none() { + cmd.env(key, value.resolve(config)); + } + } + Ok(()) +} diff --git a/src/tools/cargo/src/cargo/core/compiler/standard_lib.rs b/src/tools/cargo/src/cargo/core/compiler/standard_lib.rs index b5ac0c997..c456c58d5 100644 --- a/src/tools/cargo/src/cargo/core/compiler/standard_lib.rs +++ b/src/tools/cargo/src/cargo/core/compiler/standard_lib.rs @@ -92,7 +92,7 @@ pub fn resolve_std<'cfg>( String::from("library/std"), String::from("library/core"), String::from("library/alloc"), - String::from("library/test"), + String::from("library/sysroot"), ]; let ws_config = crate::core::WorkspaceConfig::Root(crate::core::WorkspaceRootConfig::new( &src_path, @@ -114,13 +114,13 @@ pub fn resolve_std<'cfg>( let config = ws.config(); // This is a delicate hack. In order for features to resolve correctly, // the resolver needs to run a specific "current" member of the workspace. - // Thus, in order to set the features for `std`, we need to set `libtest` - // to be the "current" member. `libtest` is the root, and all other + // Thus, in order to set the features for `std`, we need to set `sysroot` + // to be the "current" member. `sysroot` is the root, and all other // standard library crates are dependencies from there. Since none of the // other crates need to alter their features, this should be fine, for // now. Perhaps in the future features will be decoupled from the resolver // and it will be easier to control feature selection. - let current_manifest = src_path.join("library/test/Cargo.toml"); + let current_manifest = src_path.join("library/sysroot/Cargo.toml"); // TODO: Consider doing something to enforce --locked? Or to prevent the // lock file from being written, such as setting ephemeral. let mut std_ws = Workspace::new_virtual(src_path, current_manifest, virtual_manifest, config)?; @@ -128,10 +128,10 @@ pub fn resolve_std<'cfg>( // `[dev-dependencies]`. No need for us to generate a `Resolve` which has // those included because we'll never use them anyway. std_ws.set_require_optional_deps(false); - // `test` is not in the default set because it is optional, but it needs - // to be part of the resolve in case we do need it. + // `sysroot` is not in the default set because it is optional, but it needs + // to be part of the resolve in case we do need it or `libtest`. let mut spec_pkgs = Vec::from(crates); - spec_pkgs.push("test".to_string()); + spec_pkgs.push("sysroot".to_string()); let spec = Packages::Packages(spec_pkgs); let specs = spec.to_package_id_specs(&std_ws)?; let features = match &config.cli_unstable().build_std_features { diff --git a/src/tools/cargo/src/cargo/core/compiler/unit_dependencies.rs b/src/tools/cargo/src/cargo/core/compiler/unit_dependencies.rs index 68fc1e519..3bf8b0c77 100644 --- a/src/tools/cargo/src/cargo/core/compiler/unit_dependencies.rs +++ b/src/tools/cargo/src/cargo/core/compiler/unit_dependencies.rs @@ -149,7 +149,7 @@ pub fn build_unit_dependencies<'a, 'cfg>( /// Compute all the dependencies for the standard library. fn calc_deps_of_std( - mut state: &mut State<'_, '_>, + state: &mut State<'_, '_>, std_roots: &HashMap<CompileKind, Vec<Unit>>, ) -> CargoResult<Option<UnitGraph>> { if std_roots.is_empty() { diff --git a/src/tools/cargo/src/cargo/core/features.rs b/src/tools/cargo/src/cargo/core/features.rs index 7f16e79cf..d56054a0a 100644 --- a/src/tools/cargo/src/cargo/core/features.rs +++ b/src/tools/cargo/src/cargo/core/features.rs @@ -585,19 +585,19 @@ impl Features { feature_name, feature.version ); if self.is_local { - drop(writeln!( + let _ = writeln!( msg, "Remove the feature from Cargo.toml to remove this error." - )); + ); } else { - drop(writeln!( + let _ = writeln!( msg, "This package cannot be used with this version of Cargo, \ as the unstable feature `{}` is no longer supported.", feature_name - )); + ); } - drop(writeln!(msg, "{}", see_docs())); + let _ = writeln!(msg, "{}", see_docs()); bail!(msg); } } @@ -629,32 +629,29 @@ impl Features { if self.nightly_features_allowed { if self.is_local { - drop(writeln!( + let _ = writeln!( msg, "Consider adding `cargo-features = [\"{}\"]` \ to the top of Cargo.toml (above the [package] table) \ to tell Cargo you are opting in to use this unstable feature.", feature_name - )); + ); } else { - drop(writeln!( - msg, - "Consider trying a more recent nightly release." - )); + let _ = writeln!(msg, "Consider trying a more recent nightly release."); } } else { - drop(writeln!( + let _ = writeln!( msg, "Consider trying a newer version of Cargo \ (this may require the nightly release)." - )); + ); } - drop(writeln!( + let _ = writeln!( msg, "See https://doc.rust-lang.org/nightly/cargo/{} for more information \ about the status of this feature.", feature.docs - )); + ); bail!("{}", msg); } @@ -733,6 +730,8 @@ unstable_cli_options!( unstable_options: bool = ("Allow the usage of unstable options"), skip_rustdoc_fingerprint: bool = (HIDDEN), rustdoc_scrape_examples: bool = ("Allows Rustdoc to scrape code examples from reverse-dependencies"), + msrv_policy: bool = ("Enable rust-version aware policy within cargo"), + lints: bool = ("Pass `[lints]` to the linting tools"), ); const STABILIZED_COMPILE_PROGRESS: &str = "The progress bar is now always \ @@ -1095,6 +1094,8 @@ impl CliUnstable { "timings" => stabilized_warn(k, "1.60", STABILIZED_TIMINGS), "codegen-backend" => self.codegen_backend = parse_empty(k, v)?, "profile-rustflags" => self.profile_rustflags = parse_empty(k, v)?, + "msrv-policy" => self.msrv_policy = parse_empty(k, v)?, + "lints" => self.lints = parse_empty(k, v)?, _ => bail!("unknown `-Z` flag specified: {}", k), } diff --git a/src/tools/cargo/src/cargo/core/manifest.rs b/src/tools/cargo/src/cargo/core/manifest.rs index 182882dad..98498ead8 100644 --- a/src/tools/cargo/src/cargo/core/manifest.rs +++ b/src/tools/cargo/src/cargo/core/manifest.rs @@ -63,6 +63,7 @@ pub struct Manifest { default_run: Option<String>, metabuild: Option<Vec<String>>, resolve_behavior: Option<ResolveBehavior>, + lint_rustflags: Vec<String>, } /// When parsing `Cargo.toml`, some warnings should silenced @@ -110,6 +111,7 @@ pub struct ManifestMetadata { pub documentation: Option<String>, // URL pub badges: BTreeMap<String, BTreeMap<String, String>>, pub links: Option<String>, + pub rust_version: Option<String>, } #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] @@ -404,6 +406,7 @@ impl Manifest { original: Rc<TomlManifest>, metabuild: Option<Vec<String>>, resolve_behavior: Option<ResolveBehavior>, + lint_rustflags: Vec<String>, ) -> Manifest { Manifest { summary, @@ -429,6 +432,7 @@ impl Manifest { default_run, metabuild, resolve_behavior, + lint_rustflags, } } @@ -513,6 +517,11 @@ impl Manifest { self.resolve_behavior } + /// `RUSTFLAGS` from the `[lints]` table + pub fn lint_rustflags(&self) -> &[String] { + self.lint_rustflags.as_slice() + } + pub fn map_source(self, to_replace: SourceId, replace_with: SourceId) -> Manifest { Manifest { summary: self.summary.map_source(to_replace, replace_with), diff --git a/src/tools/cargo/src/cargo/core/package_id_spec.rs b/src/tools/cargo/src/cargo/core/package_id_spec.rs index 29043b963..267ea3ffd 100644 --- a/src/tools/cargo/src/cargo/core/package_id_spec.rs +++ b/src/tools/cargo/src/cargo/core/package_id_spec.rs @@ -7,9 +7,9 @@ use serde::{de, ser}; use url::Url; use crate::core::PackageId; +use crate::util::edit_distance; use crate::util::errors::CargoResult; use crate::util::interning::InternedString; -use crate::util::lev_distance; use crate::util::{validate_package_name, IntoUrl, ToSemver}; /// Some or all of the data required to identify a package: @@ -88,7 +88,7 @@ impl PackageIdSpec { { let i: Vec<_> = i.into_iter().collect(); let spec = PackageIdSpec::parse(spec).with_context(|| { - let suggestion = lev_distance::closest_msg(spec, i.iter(), |id| id.name().as_str()); + let suggestion = edit_distance::closest_msg(spec, i.iter(), |id| id.name().as_str()); format!("invalid package ID specification: `{}`{}", spec, suggestion) })?; spec.query(i) @@ -229,7 +229,7 @@ impl PackageIdSpec { ); } if suggestion.is_empty() { - suggestion.push_str(&lev_distance::closest_msg( + suggestion.push_str(&edit_distance::closest_msg( &self.name, all_ids.iter(), |id| id.name().as_str(), diff --git a/src/tools/cargo/src/cargo/core/profiles.rs b/src/tools/cargo/src/cargo/core/profiles.rs index 51d19e32e..3831f18c2 100644 --- a/src/tools/cargo/src/cargo/core/profiles.rs +++ b/src/tools/cargo/src/cargo/core/profiles.rs @@ -26,7 +26,9 @@ use crate::core::dependency::Artifact; use crate::core::resolver::features::FeaturesFor; use crate::core::{PackageId, PackageIdSpec, Resolve, Shell, Target, Workspace}; use crate::util::interning::InternedString; -use crate::util::toml::{ProfilePackageSpec, StringOrBool, TomlProfile, TomlProfiles, U32OrBool}; +use crate::util::toml::{ + ProfilePackageSpec, StringOrBool, TomlDebugInfo, TomlProfile, TomlProfiles, +}; use crate::util::{closest_msg, config, CargoResult, Config}; use anyhow::{bail, Context as _}; use std::collections::{BTreeMap, HashMap, HashSet}; @@ -276,15 +278,13 @@ impl Profiles { // platform which has a stable `-Csplit-debuginfo` option for rustc, // and it's typically much faster than running `dsymutil` on all builds // in incremental cases. - if let Some(debug) = profile.debuginfo.to_option() { - if profile.split_debuginfo.is_none() && debug > 0 { - let target = match &kind { - CompileKind::Host => self.rustc_host.as_str(), - CompileKind::Target(target) => target.short_name(), - }; - if target.contains("-apple-") { - profile.split_debuginfo = Some(InternedString::new("unpacked")); - } + if profile.debuginfo.is_turned_on() && profile.split_debuginfo.is_none() { + let target = match &kind { + CompileKind::Host => self.rustc_host.as_str(), + CompileKind::Target(target) => target.short_name(), + }; + if target.contains("-apple-") { + profile.split_debuginfo = Some(InternedString::new("unpacked")); } } @@ -528,11 +528,8 @@ fn merge_profile(profile: &mut Profile, toml: &TomlProfile) { if toml.codegen_units.is_some() { profile.codegen_units = toml.codegen_units; } - match toml.debug { - Some(U32OrBool::U32(debug)) => profile.debuginfo = DebugInfo::Explicit(debug), - Some(U32OrBool::Bool(true)) => profile.debuginfo = DebugInfo::Explicit(2), - Some(U32OrBool::Bool(false)) => profile.debuginfo = DebugInfo::None, - None => {} + if let Some(debuginfo) = toml.debug { + profile.debuginfo = DebugInfo::Explicit(debuginfo); } if let Some(debug_assertions) = toml.debug_assertions { profile.debug_assertions = debug_assertions; @@ -683,7 +680,7 @@ impl Profile { Profile { name: InternedString::new("dev"), root: ProfileRoot::Debug, - debuginfo: DebugInfo::Explicit(2), + debuginfo: DebugInfo::Explicit(TomlDebugInfo::Full), debug_assertions: true, overflow_checks: true, incremental: true, @@ -704,7 +701,7 @@ impl Profile { /// Compares all fields except `name`, which doesn't affect compilation. /// This is necessary for `Unit` deduplication for things like "test" and /// "dev" which are essentially the same. - fn comparable(&self) -> impl Hash + Eq { + fn comparable(&self) -> impl Hash + Eq + '_ { ( self.opt_level, self.lto, @@ -715,9 +712,8 @@ impl Profile { self.debug_assertions, self.overflow_checks, self.rpath, - self.incremental, - self.panic, - self.strip, + (self.incremental, self.panic, self.strip), + &self.rustflags, ) } } @@ -743,7 +739,7 @@ pub enum DebugInfo { /// No debuginfo level was set. None, /// A debuginfo level that is explicitly set, by a profile or a user. - Explicit(u32), + Explicit(TomlDebugInfo), /// For internal purposes: a deferred debuginfo level that can be optimized /// away, but has this value otherwise. /// @@ -753,22 +749,22 @@ pub enum DebugInfo { /// faster to build (see [DebugInfo::weaken]). /// /// In all other situations, this level value will be the one to use. - Deferred(u32), + Deferred(TomlDebugInfo), } impl DebugInfo { /// The main way to interact with this debuginfo level, turning it into an Option. - pub fn to_option(&self) -> Option<u32> { + pub fn to_option(self) -> Option<TomlDebugInfo> { match self { DebugInfo::None => None, - DebugInfo::Explicit(v) | DebugInfo::Deferred(v) => Some(*v), + DebugInfo::Explicit(v) | DebugInfo::Deferred(v) => Some(v), } } - /// Returns true if the debuginfo level is high enough (at least 1). Helper + /// Returns true if any debuginfo will be generated. Helper /// for a common operation on the usual `Option` representation. pub(crate) fn is_turned_on(&self) -> bool { - self.to_option().unwrap_or(0) != 0 + !matches!(self.to_option(), None | Some(TomlDebugInfo::None)) } pub(crate) fn is_deferred(&self) -> bool { @@ -784,8 +780,12 @@ impl DebugInfo { } /// Reset to the lowest level: no debuginfo. + /// If it is explicitly set, keep it explicit. pub(crate) fn weaken(self) -> Self { - DebugInfo::None + match self { + DebugInfo::None => DebugInfo::None, + _ => DebugInfo::Explicit(TomlDebugInfo::None), + } } } diff --git a/src/tools/cargo/src/cargo/core/resolver/dep_cache.rs b/src/tools/cargo/src/cargo/core/resolver/dep_cache.rs index 4fd275385..54b0ce97f 100644 --- a/src/tools/cargo/src/cargo/core/resolver/dep_cache.rs +++ b/src/tools/cargo/src/cargo/core/resolver/dep_cache.rs @@ -455,7 +455,12 @@ impl Requirements<'_> { .iter() .any(|dep| dep.name_in_toml() == package && dep.is_optional()) { - self.require_feature(package)?; + // This optional dependency may not have an implicit feature of + // the same name if the `dep:` syntax is used to avoid creating + // that implicit feature. + if self.summary.features().contains_key(&package) { + self.require_feature(package)?; + } } self.deps.entry(package).or_default().insert(feat); Ok(()) diff --git a/src/tools/cargo/src/cargo/core/resolver/errors.rs b/src/tools/cargo/src/cargo/core/resolver/errors.rs index d75240df6..ca5c833f4 100644 --- a/src/tools/cargo/src/cargo/core/resolver/errors.rs +++ b/src/tools/cargo/src/cargo/core/resolver/errors.rs @@ -2,7 +2,7 @@ use std::fmt; use std::task::Poll; use crate::core::{Dependency, PackageId, QueryKind, Registry, Summary}; -use crate::util::lev_distance::lev_distance; +use crate::util::edit_distance::edit_distance; use crate::util::{Config, VersionExt}; use anyhow::Error; @@ -308,8 +308,7 @@ pub(super) fn activation_error( candidates.dedup_by(|a, b| a.name() == b.name()); let mut candidates: Vec<_> = candidates .iter() - .map(|n| (lev_distance(&*new_dep.package_name(), &*n.name()), n)) - .filter(|&(d, _)| d < 4) + .filter_map(|n| Some((edit_distance(&*new_dep.package_name(), &*n.name(), 3)?, n))) .collect(); candidates.sort_by_key(|o| o.0); let mut msg: String; diff --git a/src/tools/cargo/src/cargo/core/resolver/features.rs b/src/tools/cargo/src/cargo/core/resolver/features.rs index e2f2bd5c5..6b79722ca 100644 --- a/src/tools/cargo/src/cargo/core/resolver/features.rs +++ b/src/tools/cargo/src/cargo/core/resolver/features.rs @@ -717,7 +717,15 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> { // The old behavior before weak dependencies were // added is to also enables a feature of the same // name. - self.activate_rec(pkg_id, fk, dep_name)?; + // + // Don't enable if the implicit optional dependency + // feature wasn't created due to `dep:` hiding. + // See rust-lang/cargo#10788 and rust-lang/cargo#12130 + let summary = self.resolve.summary(pkg_id); + let feature_map = summary.features(); + if feature_map.contains_key(&dep_name) { + self.activate_rec(pkg_id, fk, dep_name)?; + } } } // Activate the feature on the dependency. diff --git a/src/tools/cargo/src/cargo/core/resolver/version_prefs.rs b/src/tools/cargo/src/cargo/core/resolver/version_prefs.rs index 73cce5db8..002f11ff8 100644 --- a/src/tools/cargo/src/cargo/core/resolver/version_prefs.rs +++ b/src/tools/cargo/src/cargo/core/resolver/version_prefs.rs @@ -100,7 +100,15 @@ mod test { let pkg_id = pkgid(name, version); let config = Config::default().unwrap(); let features = BTreeMap::new(); - Summary::new(&config, pkg_id, Vec::new(), &features, None::<&String>).unwrap() + Summary::new( + &config, + pkg_id, + Vec::new(), + &features, + None::<&String>, + None::<&String>, + ) + .unwrap() } fn describe(summaries: &Vec<Summary>) -> String { diff --git a/src/tools/cargo/src/cargo/core/shell.rs b/src/tools/cargo/src/cargo/core/shell.rs index fdae617c4..f74bde257 100644 --- a/src/tools/cargo/src/cargo/core/shell.rs +++ b/src/tools/cargo/src/cargo/core/shell.rs @@ -563,13 +563,13 @@ mod imp { use windows_sys::core::PCSTR; use windows_sys::Win32::Foundation::CloseHandle; use windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE; + use windows_sys::Win32::Foundation::{GENERIC_READ, GENERIC_WRITE}; use windows_sys::Win32::Storage::FileSystem::{ CreateFileA, FILE_SHARE_READ, FILE_SHARE_WRITE, OPEN_EXISTING, }; use windows_sys::Win32::System::Console::{ GetConsoleScreenBufferInfo, GetStdHandle, CONSOLE_SCREEN_BUFFER_INFO, STD_ERROR_HANDLE, }; - use windows_sys::Win32::System::SystemServices::{GENERIC_READ, GENERIC_WRITE}; pub(super) use super::{default_err_erase_line as err_erase_line, TtyWidth}; diff --git a/src/tools/cargo/src/cargo/core/source/mod.rs b/src/tools/cargo/src/cargo/core/source/mod.rs index dca71b64e..6ca614d34 100644 --- a/src/tools/cargo/src/cargo/core/source/mod.rs +++ b/src/tools/cargo/src/cargo/core/source/mod.rs @@ -1,3 +1,18 @@ +//! Fundamental types and traits for sources of Cargo packages. +//! +//! A source is a provider that contains source files and metadata of packages. +//! It provides a number of methods to fetch those package informations, for +//! example, querying metadata or downloading files for a package. These +//! informations then can be used as dependencies for other Cargo packages. +//! +//! Notably, this module contains +//! +//! * [`Source`] trait as an abstraction of different sources +//! * [`SourceMap`] struct as a map of all available sources +//! * [`SourceId`] struct as an unique identifier for a certain source +//! +//! For implementations of `Source` trait, see [`crate::sources`]. + use std::collections::hash_map::HashMap; use std::fmt; use std::task::Poll; @@ -10,25 +25,48 @@ mod source_id; pub use self::source_id::{GitReference, SourceId}; -/// Something that finds and downloads remote packages based on names and versions. +/// An abstraction of different sources of Cargo packages. +/// +/// The [`Source`] trait generalizes the API to interact with these providers. +/// For example, +/// +/// * [`Source::query`] is for querying package metadata on a given +/// [`Dependency`] requested by a Cargo manifest. +/// * [`Source::download`] is for fetching the full package information on +/// given names and versions. +/// * [`Source::source_id`] is for defining an unique identifier of a source to +/// distinguish one source from another, keeping Cargo safe from [dependency +/// confusion attack]. +/// +/// Normally, developers don't need to implement their own [`Source`]s. Cargo +/// provides several kinds of sources implementations that should cover almost +/// all use cases. See [`crate::sources`] for implementations provided by Cargo. +/// +/// [dependency confusion attack]: https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610 pub trait Source { - /// Returns the `SourceId` corresponding to this source. + /// Returns the [`SourceId`] corresponding to this source. fn source_id(&self) -> SourceId; - /// Returns the replaced `SourceId` corresponding to this source. + /// Returns the replaced [`SourceId`] corresponding to this source. fn replaced_source_id(&self) -> SourceId { self.source_id() } - /// Returns whether or not this source will return summaries with + /// Returns whether or not this source will return [`Summary`] items with /// checksums listed. fn supports_checksums(&self) -> bool; - /// Returns whether or not this source will return summaries with - /// the `precise` field in the source id listed. + /// Returns whether or not this source will return [`Summary`] items with + /// the `precise` field in the [`SourceId`] listed. fn requires_precise(&self) -> bool; /// Attempts to find the packages that match a dependency request. + /// + /// Usually you should call [`Source::block_until_ready`] somewhere and + /// wait until package informations become available. Otherwise any query + /// may return a [`Poll::Pending`]. + /// + /// The `f` argument is expected to get called when any [`Summary`] becomes available. fn query( &mut self, dep: &Dependency, @@ -36,6 +74,8 @@ pub trait Source { f: &mut dyn FnMut(Summary), ) -> Poll<CargoResult<()>>; + /// Gathers the result from [`Source::query`] as a list of [`Summary`] items + /// when they become available. fn query_vec(&mut self, dep: &Dependency, kind: QueryKind) -> Poll<CargoResult<Vec<Summary>>> { let mut ret = Vec::new(); self.query(dep, kind, &mut |s| ret.push(s)).map_ok(|_| ret) @@ -50,6 +90,7 @@ pub trait Source { /// Fetches the full package for each name and version specified. fn download(&mut self, package: PackageId) -> CargoResult<MaybePackage>; + /// Fetches the full package **immediately** for each name and version specified. fn download_now(self: Box<Self>, package: PackageId, config: &Config) -> CargoResult<Package> where Self: std::marker::Sized, @@ -61,7 +102,8 @@ pub trait Source { Ok(Package::clone(pkg)) } - fn finish_download(&mut self, package: PackageId, contents: Vec<u8>) -> CargoResult<Package>; + /// Finalizes the download contents of the given [`PackageId`] to a [`Package`]. + fn finish_download(&mut self, pkg_id: PackageId, contents: Vec<u8>) -> CargoResult<Package>; /// Generates a unique string which represents the fingerprint of the /// current state of the source. @@ -103,56 +145,67 @@ pub trait Source { /// as yanked. This ignores the yanked whitelist. fn is_yanked(&mut self, _pkg: PackageId) -> Poll<CargoResult<bool>>; - /// Block until all outstanding Poll::Pending requests are `Poll::Ready`. + /// Block until all outstanding [`Poll::Pending`] requests are [`Poll::Ready`]. /// /// After calling this function, the source should return `Poll::Ready` for /// any queries that previously returned `Poll::Pending`. /// - /// If no queries previously returned `Poll::Pending`, and `invalidate_cache` + /// If no queries previously returned `Poll::Pending`, and [`Source::invalidate_cache`] /// was not called, this function should be a no-op. fn block_until_ready(&mut self) -> CargoResult<()>; } +/// Defines how a dependency query will be performed for a [`Source`]. #[derive(Copy, Clone, PartialEq, Eq)] pub enum QueryKind { + /// A query for packages exactly matching the given dependency requirement. + /// + /// Each source gets to define what `exact` means for it. Exact, + /// A query for packages close to the given dependency requirement. + /// /// Each source gets to define what `close` means for it. + /// /// Path/Git sources may return all dependencies that are at that URI, - /// whereas an `Index` source may return dependencies that have the same canonicalization. + /// whereas an `Registry` source may return dependencies that have the same + /// canonicalization. Fuzzy, } +/// A download status that represents if a [`Package`] has already been +/// downloaded, or if not then a location to download. pub enum MaybePackage { + /// The [`Package`] is already downloaded. Ready(Package), + /// Not yet downloaded. Here is the URL to download the [`Package`] from. Download { + /// URL to download the content. url: String, + /// Text to display to the user of what is being downloaded. descriptor: String, + /// Authorization data that may be required to attach when downloading. authorization: Option<String>, }, } +/// A blanket implementation forwards all methods to [`Source`]. impl<'a, T: Source + ?Sized + 'a> Source for Box<T> { - /// Forwards to `Source::source_id`. fn source_id(&self) -> SourceId { (**self).source_id() } - /// Forwards to `Source::replaced_source_id`. fn replaced_source_id(&self) -> SourceId { (**self).replaced_source_id() } - /// Forwards to `Source::supports_checksums`. fn supports_checksums(&self) -> bool { (**self).supports_checksums() } - /// Forwards to `Source::requires_precise`. fn requires_precise(&self) -> bool { (**self).requires_precise() } - /// Forwards to `Source::query`. fn query( &mut self, dep: &Dependency, @@ -170,7 +223,6 @@ impl<'a, T: Source + ?Sized + 'a> Source for Box<T> { (**self).set_quiet(quiet) } - /// Forwards to `Source::download`. fn download(&mut self, id: PackageId) -> CargoResult<MaybePackage> { (**self).download(id) } @@ -179,12 +231,10 @@ impl<'a, T: Source + ?Sized + 'a> Source for Box<T> { (**self).finish_download(id, data) } - /// Forwards to `Source::fingerprint`. fn fingerprint(&self, pkg: &Package) -> CargoResult<String> { (**self).fingerprint(pkg) } - /// Forwards to `Source::verify`. fn verify(&self, pkg: PackageId) -> CargoResult<()> { (**self).verify(pkg) } @@ -210,6 +260,7 @@ impl<'a, T: Source + ?Sized + 'a> Source for Box<T> { } } +/// A blanket implementation forwards all methods to [`Source`]. impl<'a, T: Source + ?Sized + 'a> Source for &'a mut T { fn source_id(&self) -> SourceId { (**self).source_id() @@ -281,7 +332,7 @@ impl<'a, T: Source + ?Sized + 'a> Source for &'a mut T { } } -/// A `HashMap` of `SourceId` -> `Box<Source>`. +/// A [`HashMap`] of [`SourceId`] to `Box<Source>`. #[derive(Default)] pub struct SourceMap<'src> { map: HashMap<SourceId, Box<dyn Source + 'src>>, @@ -313,7 +364,7 @@ impl<'src> SourceMap<'src> { self.map.get_mut(&id).map(|s| s.as_mut()) } - /// Like `HashMap::insert`, but derives the `SourceId` key from the `Source`. + /// Like `HashMap::insert`, but derives the [`SourceId`] key from the [`Source`]. pub fn insert(&mut self, source: Box<dyn Source + 'src>) { let id = source.source_id(); self.map.insert(id, source); diff --git a/src/tools/cargo/src/cargo/core/source/source_id.rs b/src/tools/cargo/src/cargo/core/source/source_id.rs index 034d7ed59..c369dab16 100644 --- a/src/tools/cargo/src/cargo/core/source/source_id.rs +++ b/src/tools/cargo/src/cargo/core/source/source_id.rs @@ -20,16 +20,31 @@ lazy_static::lazy_static! { } /// Unique identifier for a source of packages. +/// +/// Cargo uniquely identifies packages using [`PackageId`], a combination of the +/// package name, version, and the code source. `SourceId` exactly represents +/// the "code source" in `PackageId`. See [`SourceId::hash`] to learn what are +/// taken into account for the uniqueness of a source. +/// +/// `SourceId` is usually associated with an instance of [`Source`], which is +/// supposed to provide a `SourceId` via [`Source::source_id`] method. +/// +/// [`Source`]: super::Source +/// [`Source::source_id`]: super::Source::source_id +/// [`PackageId`]: super::super::PackageId #[derive(Clone, Copy, Eq, Debug)] pub struct SourceId { inner: &'static SourceIdInner, } +/// The interned version of [`SourceId`] to avoid excessive clones and borrows. +/// Values are cached in `SOURCE_ID_CACHE` once created. #[derive(Eq, Clone, Debug)] struct SourceIdInner { /// The source URL. url: Url, - /// The canonical version of the above url + /// The canonical version of the above url. See [`CanonicalUrl`] to learn + /// why it is needed and how it normalizes a URL. canonical_url: CanonicalUrl, /// The source kind. kind: SourceKind, @@ -45,8 +60,8 @@ struct SourceIdInner { alt_registry_key: Option<String>, } -/// The possible kinds of code source. Along with `SourceIdInner`, this fully defines the -/// source. +/// The possible kinds of code source. +/// Along with [`SourceIdInner`], this fully defines the source. #[derive(Debug, Clone, PartialEq, Eq, Hash)] enum SourceKind { /// A git repository. @@ -70,7 +85,8 @@ pub enum GitReference { Tag(String), /// From a branch. Branch(String), - /// From a specific revision. + /// From a specific revision. Can be a commit hash (either short or full), + /// or a named reference like `refs/pull/493/head`. Rev(String), /// The default branch of the repository, the reference named `HEAD`. DefaultBranch, @@ -100,6 +116,7 @@ impl SourceId { Ok(source_id) } + /// Interns the value and returns the wrapped type. fn wrap(inner: SourceIdInner) -> SourceId { let mut cache = SOURCE_ID_CACHE.lock().unwrap(); let inner = cache.get(&inner).cloned().unwrap_or_else(|| { @@ -172,7 +189,7 @@ impl SourceId { } } - /// A view of the `SourceId` that can be `Display`ed as a URL. + /// A view of the [`SourceId`] that can be `Display`ed as a URL. pub fn as_url(&self) -> SourceIdAsUrl<'_> { SourceIdAsUrl { inner: &*self.inner, @@ -208,7 +225,7 @@ impl SourceId { SourceId::new(kind, url.to_owned(), Some(name)) } - /// Creates a SourceId from a local registry path. + /// Creates a `SourceId` from a local registry path. pub fn for_local_registry(path: &Path) -> CargoResult<SourceId> { let url = path.into_url()?; SourceId::new(SourceKind::LocalRegistry, url, None) @@ -287,6 +304,7 @@ impl SourceId { &self.inner.canonical_url } + /// Displays the text "crates.io index" for Cargo shell status output. pub fn display_index(self) -> String { if self.is_crates_io() { format!("{} index", CRATES_IO_DOMAIN) @@ -295,6 +313,7 @@ impl SourceId { } } + /// Displays the name of a registry if it has one. Otherwise just the URL. pub fn display_registry_name(self) -> String { if self.is_crates_io() { CRATES_IO_REGISTRY.to_string() @@ -360,6 +379,8 @@ impl SourceId { } /// Creates an implementation of `Source` corresponding to this ID. + /// + /// * `yanked_whitelist` --- Packages allowed to be used, even if they are yanked. pub fn load<'a>( self, config: &'a Config, @@ -434,7 +455,7 @@ impl SourceId { /// Hashes `self`. /// /// For paths, remove the workspace prefix so the same source will give the - /// same hash in different locations. + /// same hash in different locations, helping reproducible builds. pub fn stable_hash<S: hash::Hasher>(self, workspace: &Path, into: &mut S) { if self.is_path() { if let Ok(p) = self @@ -563,9 +584,9 @@ impl fmt::Display for SourceId { } } -// The hash of SourceId is used in the name of some Cargo folders, so shouldn't -// vary. `as_str` gives the serialisation of a url (which has a spec) and so -// insulates against possible changes in how the url crate does hashing. +/// The hash of SourceId is used in the name of some Cargo folders, so shouldn't +/// vary. `as_str` gives the serialisation of a url (which has a spec) and so +/// insulates against possible changes in how the url crate does hashing. impl Hash for SourceId { fn hash<S: hash::Hasher>(&self, into: &mut S) { self.inner.kind.hash(into); @@ -576,13 +597,14 @@ impl Hash for SourceId { } } +/// The hash of `SourceIdInner` is used to retrieve its interned value from +/// `SOURCE_ID_CACHE`. We only care about fields that make `SourceIdInner` +/// unique. Optional fields not affecting the uniqueness must be excluded, +/// such as [`name`] and [`alt_registry_key`]. That's why this is not derived. +/// +/// [`name`]: SourceIdInner::name +/// [`alt_registry_key`]: SourceIdInner::alt_registry_key impl Hash for SourceIdInner { - /// The hash of `SourceIdInner` is used to retrieve its interned value. We - /// only care about fields that make `SourceIdInner` unique, which are: - /// - /// - `kind` - /// - `precise` - /// - `canonical_url` fn hash<S: hash::Hasher>(&self, into: &mut S) { self.kind.hash(into); self.precise.hash(into); @@ -590,8 +612,8 @@ impl Hash for SourceIdInner { } } +/// This implementation must be synced with [`SourceIdInner::hash`]. impl PartialEq for SourceIdInner { - /// This implementation must be synced with [`SourceIdInner::hash`]. fn eq(&self, other: &Self) -> bool { self.kind == other.kind && self.precise == other.precise @@ -599,66 +621,66 @@ impl PartialEq for SourceIdInner { } } -// forward to `Ord` +/// Forwards to `Ord` impl PartialOrd for SourceKind { fn partial_cmp(&self, other: &SourceKind) -> Option<Ordering> { Some(self.cmp(other)) } } -// Note that this is specifically not derived on `SourceKind` although the -// implementation here is very similar to what it might look like if it were -// otherwise derived. -// -// The reason for this is somewhat obtuse. First of all the hash value of -// `SourceKind` makes its way into `~/.cargo/registry/index/github.com-XXXX` -// which means that changes to the hash means that all Rust users need to -// redownload the crates.io index and all their crates. If possible we strive to -// not change this to make this redownloading behavior happen as little as -// possible. How is this connected to `Ord` you might ask? That's a good -// question! -// -// Since the beginning of time `SourceKind` has had `#[derive(Hash)]`. It for -// the longest time *also* derived the `Ord` and `PartialOrd` traits. In #8522, -// however, the implementation of `Ord` changed. This handwritten implementation -// forgot to sync itself with the originally derived implementation, namely -// placing git dependencies as sorted after all other dependencies instead of -// first as before. -// -// This regression in #8522 (Rust 1.47) went unnoticed. When we switched back -// to a derived implementation in #9133 (Rust 1.52 beta) we only then ironically -// saw an issue (#9334). In #9334 it was observed that stable Rust at the time -// (1.51) was sorting git dependencies last, whereas Rust 1.52 beta would sort -// git dependencies first. This is because the `PartialOrd` implementation in -// 1.51 used #8522, the buggy implementation, which put git deps last. In 1.52 -// it was (unknowingly) restored to the pre-1.47 behavior with git dependencies -// first. -// -// Because the breakage was only witnessed after the original breakage, this -// trait implementation is preserving the "broken" behavior. Put a different way: -// -// * Rust pre-1.47 sorted git deps first. -// * Rust 1.47 to Rust 1.51 sorted git deps last, a breaking change (#8522) that -// was never noticed. -// * Rust 1.52 restored the pre-1.47 behavior (#9133, without knowing it did -// so), and breakage was witnessed by actual users due to difference with -// 1.51. -// * Rust 1.52 (the source as it lives now) was fixed to match the 1.47-1.51 -// behavior (#9383), which is now considered intentionally breaking from the -// pre-1.47 behavior. -// -// Note that this was all discovered when Rust 1.53 was in nightly and 1.52 was -// in beta. #9133 was in both beta and nightly at the time of discovery. For -// 1.52 #9383 reverted #9133, meaning 1.52 is the same as 1.51. On nightly -// (1.53) #9397 was created to fix the regression introduced by #9133 relative -// to the current stable (1.51). -// -// That's all a long winded way of saying "it's weird that git deps hash first -// and are sorted last, but it's the way it is right now". The author of this -// comment chose to handwrite the `Ord` implementation instead of the `Hash` -// implementation, but it's only required that at most one of them is -// hand-written because the other can be derived. Perhaps one day in -// the future someone can figure out how to remove this behavior. +/// Note that this is specifically not derived on `SourceKind` although the +/// implementation here is very similar to what it might look like if it were +/// otherwise derived. +/// +/// The reason for this is somewhat obtuse. First of all the hash value of +/// `SourceKind` makes its way into `~/.cargo/registry/index/github.com-XXXX` +/// which means that changes to the hash means that all Rust users need to +/// redownload the crates.io index and all their crates. If possible we strive +/// to not change this to make this redownloading behavior happen as little as +/// possible. How is this connected to `Ord` you might ask? That's a good +/// question! +/// +/// Since the beginning of time `SourceKind` has had `#[derive(Hash)]`. It for +/// the longest time *also* derived the `Ord` and `PartialOrd` traits. In #8522, +/// however, the implementation of `Ord` changed. This handwritten implementation +/// forgot to sync itself with the originally derived implementation, namely +/// placing git dependencies as sorted after all other dependencies instead of +/// first as before. +/// +/// This regression in #8522 (Rust 1.47) went unnoticed. When we switched back +/// to a derived implementation in #9133 (Rust 1.52 beta) we only then ironically +/// saw an issue (#9334). In #9334 it was observed that stable Rust at the time +/// (1.51) was sorting git dependencies last, whereas Rust 1.52 beta would sort +/// git dependencies first. This is because the `PartialOrd` implementation in +/// 1.51 used #8522, the buggy implementation, which put git deps last. In 1.52 +/// it was (unknowingly) restored to the pre-1.47 behavior with git dependencies +/// first. +/// +/// Because the breakage was only witnessed after the original breakage, this +/// trait implementation is preserving the "broken" behavior. Put a different way: +/// +/// * Rust pre-1.47 sorted git deps first. +/// * Rust 1.47 to Rust 1.51 sorted git deps last, a breaking change (#8522) that +/// was never noticed. +/// * Rust 1.52 restored the pre-1.47 behavior (#9133, without knowing it did +/// so), and breakage was witnessed by actual users due to difference with +/// 1.51. +/// * Rust 1.52 (the source as it lives now) was fixed to match the 1.47-1.51 +/// behavior (#9383), which is now considered intentionally breaking from the +/// pre-1.47 behavior. +/// +/// Note that this was all discovered when Rust 1.53 was in nightly and 1.52 was +/// in beta. #9133 was in both beta and nightly at the time of discovery. For +/// 1.52 #9383 reverted #9133, meaning 1.52 is the same as 1.51. On nightly +/// (1.53) #9397 was created to fix the regression introduced by #9133 relative +/// to the current stable (1.51). +/// +/// That's all a long winded way of saying "it's weird that git deps hash first +/// and are sorted last, but it's the way it is right now". The author of this +/// comment chose to handwrite the `Ord` implementation instead of the `Hash` +/// implementation, but it's only required that at most one of them is +/// hand-written because the other can be derived. Perhaps one day in +/// the future someone can figure out how to remove this behavior. impl Ord for SourceKind { fn cmp(&self, other: &SourceKind) -> Ordering { match (self, other) { diff --git a/src/tools/cargo/src/cargo/core/summary.rs b/src/tools/cargo/src/cargo/core/summary.rs index 8a7238e4a..2535c4482 100644 --- a/src/tools/cargo/src/cargo/core/summary.rs +++ b/src/tools/cargo/src/cargo/core/summary.rs @@ -25,6 +25,7 @@ struct Inner { features: Rc<FeatureMap>, checksum: Option<String>, links: Option<InternedString>, + rust_version: Option<InternedString>, } impl Summary { @@ -34,6 +35,7 @@ impl Summary { dependencies: Vec<Dependency>, features: &BTreeMap<InternedString, Vec<InternedString>>, links: Option<impl Into<InternedString>>, + rust_version: Option<impl Into<InternedString>>, ) -> CargoResult<Summary> { // ****CAUTION**** If you change anything here that may raise a new // error, be sure to coordinate that change with either the index @@ -55,6 +57,7 @@ impl Summary { features: Rc::new(feature_map), checksum: None, links: links.map(|l| l.into()), + rust_version: rust_version.map(|l| l.into()), }), }) } @@ -85,6 +88,10 @@ impl Summary { self.inner.links } + pub fn rust_version(&self) -> Option<InternedString> { + self.inner.rust_version + } + pub fn override_id(mut self, id: PackageId) -> Summary { Rc::make_mut(&mut self.inner).package_id = id; self diff --git a/src/tools/cargo/src/cargo/core/workspace.rs b/src/tools/cargo/src/cargo/core/workspace.rs index 12b78a69c..9922d6d33 100644 --- a/src/tools/cargo/src/cargo/core/workspace.rs +++ b/src/tools/cargo/src/cargo/core/workspace.rs @@ -19,9 +19,9 @@ use crate::core::{Dependency, FeatureValue, PackageId, PackageIdSpec}; use crate::core::{EitherManifest, Package, SourceId, VirtualManifest}; use crate::ops; use crate::sources::{PathSource, CRATES_IO_INDEX, CRATES_IO_REGISTRY}; +use crate::util::edit_distance; use crate::util::errors::{CargoResult, ManifestError}; use crate::util::interning::InternedString; -use crate::util::lev_distance; use crate::util::toml::{read_manifest, InheritableFields, TomlDependency, TomlProfiles}; use crate::util::{config::ConfigRelativePath, Config, Filesystem, IntoUrl}; use cargo_util::paths; @@ -1245,8 +1245,9 @@ impl<'cfg> Workspace<'cfg> { optional_dependency_names_per_member.insert(member, optional_dependency_names_raw); } - let levenshtein_test = - |a: InternedString, b: InternedString| lev_distance(a.as_str(), b.as_str()) < 4; + let edit_distance_test = |a: InternedString, b: InternedString| { + edit_distance(a.as_str(), b.as_str(), 3).is_some() + }; let suggestions: Vec<_> = cli_features .features @@ -1257,12 +1258,12 @@ impl<'cfg> Workspace<'cfg> { // Finds member features which are similar to the requested feature. let summary_features = summary_features .iter() - .filter(move |feature| levenshtein_test(**feature, *typo)); + .filter(move |feature| edit_distance_test(**feature, *typo)); // Finds optional dependencies which name is similar to the feature let optional_dependency_features = optional_dependency_names .iter() - .filter(move |feature| levenshtein_test(**feature, *typo)); + .filter(move |feature| edit_distance_test(**feature, *typo)); summary_features .chain(optional_dependency_features) @@ -1278,13 +1279,13 @@ impl<'cfg> Workspace<'cfg> { // Finds set of `pkg/feat` that are very similar to current `pkg/feat`. let pkg_feat_similar = dependencies_features .iter() - .filter(|(name, _)| levenshtein_test(**name, *dep_name)) + .filter(|(name, _)| edit_distance_test(**name, *dep_name)) .map(|(name, features)| { ( name, features .iter() - .filter(|feature| levenshtein_test(**feature, *dep_feature)) + .filter(|feature| edit_distance_test(**feature, *dep_feature)) .collect::<Vec<_>>(), ) }) @@ -1298,12 +1299,12 @@ impl<'cfg> Workspace<'cfg> { // Finds set of `member/optional_dep` features which name is similar to current `pkg/feat`. let optional_dependency_features = optional_dependency_names_per_member .iter() - .filter(|(package, _)| levenshtein_test(package.name(), *dep_name)) + .filter(|(package, _)| edit_distance_test(package.name(), *dep_name)) .map(|(package, optional_dependencies)| { optional_dependencies .into_iter() .filter(|optional_dependency| { - levenshtein_test(**optional_dependency, *dep_name) + edit_distance_test(**optional_dependency, *dep_name) }) .map(move |optional_dependency| { format!("{}/{}", package.name(), optional_dependency) @@ -1314,12 +1315,12 @@ impl<'cfg> Workspace<'cfg> { // Finds set of `member/feat` features which name is similar to current `pkg/feat`. let summary_features = summary_features_per_member .iter() - .filter(|(package, _)| levenshtein_test(package.name(), *dep_name)) + .filter(|(package, _)| edit_distance_test(package.name(), *dep_name)) .map(|(package, summary_features)| { summary_features .into_iter() .filter(|summary_feature| { - levenshtein_test(**summary_feature, *dep_feature) + edit_distance_test(**summary_feature, *dep_feature) }) .map(move |summary_feature| { format!("{}/{}", package.name(), summary_feature) diff --git a/src/tools/cargo/src/cargo/lib.rs b/src/tools/cargo/src/cargo/lib.rs index f4c671fd3..31d03ad25 100644 --- a/src/tools/cargo/src/cargo/lib.rs +++ b/src/tools/cargo/src/cargo/lib.rs @@ -37,7 +37,7 @@ //! - [`core::compiler`]: //! This is the code responsible for running `rustc` and `rustdoc`. //! - [`core::compiler::build_context`]: -//! The [`BuildContext`]['core::compiler::BuildContext] is the result of the "front end" of the +//! The [`BuildContext`][core::compiler::BuildContext] is the result of the "front end" of the //! build process. This contains the graph of work to perform and any settings necessary for //! `rustc`. After this is built, the next stage of building is handled in //! [`Context`][core::compiler::Context]. @@ -86,7 +86,7 @@ //! - [`cargo-test-macro`](https://github.com/rust-lang/cargo/tree/master/crates/cargo-test-macro) //! ([nightly docs](https://doc.rust-lang.org/nightly/nightly-rustc/cargo_test_macro/index.html)): //! This is the `#[cargo_test]` proc-macro used by the test suite to define tests. -//! - [`credential`](https://github.com/rust-lang/cargo/tree/master/crates/credential) +//! - [`credential`](https://github.com/rust-lang/cargo/tree/master/credential) //! This subdirectory contains several packages for implementing the //! experimental //! [credential-process](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process) diff --git a/src/tools/cargo/src/cargo/ops/cargo_add/mod.rs b/src/tools/cargo/src/cargo/ops/cargo_add/mod.rs index 5c519ac09..11ca282ee 100644 --- a/src/tools/cargo/src/cargo/ops/cargo_add/mod.rs +++ b/src/tools/cargo/src/cargo/ops/cargo_add/mod.rs @@ -51,6 +51,8 @@ pub struct AddOptions<'a> { pub section: DepTable, /// Act as if dependencies will be added pub dry_run: bool, + /// Whether the minimum supported Rust version should be considered during resolution + pub honor_rust_version: bool, } /// Add dependencies to a manifest @@ -86,7 +88,9 @@ pub fn add(workspace: &Workspace<'_>, options: &AddOptions<'_>) -> CargoResult<( &manifest, raw, workspace, + &options.spec, &options.section, + options.honor_rust_version, options.config, &mut registry, ) @@ -256,7 +260,9 @@ fn resolve_dependency( manifest: &LocalManifest, arg: &DepOp, ws: &Workspace<'_>, + spec: &Package, section: &DepTable, + honor_rust_version: bool, config: &Config, registry: &mut PackageRegistry<'_>, ) -> CargoResult<DependencyUI> { @@ -368,7 +374,14 @@ fn resolve_dependency( } dependency = dependency.set_source(src); } else { - let latest = get_latest_dependency(&dependency, false, config, registry)?; + let latest = get_latest_dependency( + spec, + &dependency, + false, + honor_rust_version, + config, + registry, + )?; if dependency.name != latest.name { config.shell().warn(format!( @@ -518,8 +531,10 @@ fn get_existing_dependency( } fn get_latest_dependency( + spec: &Package, dependency: &Dependency, _flag_allow_prerelease: bool, + honor_rust_version: bool, config: &Config, registry: &mut PackageRegistry<'_>, ) -> CargoResult<Dependency> { @@ -529,7 +544,7 @@ fn get_latest_dependency( unreachable!("registry dependencies required, found a workspace dependency"); } MaybeWorkspace::Other(query) => { - let possibilities = loop { + let mut possibilities = loop { match registry.query_vec(&query, QueryKind::Fuzzy) { std::task::Poll::Ready(res) => { break res?; @@ -537,19 +552,79 @@ fn get_latest_dependency( std::task::Poll::Pending => registry.block_until_ready()?, } }; - let latest = possibilities - .iter() - .max_by_key(|s| { - // Fallback to a pre-release if no official release is available by sorting them as - // less. - let stable = s.version().pre.is_empty(); - (stable, s.version()) - }) - .ok_or_else(|| { - anyhow::format_err!( - "the crate `{dependency}` could not be found in registry index." - ) - })?; + + possibilities.sort_by_key(|s| { + // Fallback to a pre-release if no official release is available by sorting them as + // less. + let stable = s.version().pre.is_empty(); + (stable, s.version().clone()) + }); + + let mut latest = possibilities.last().ok_or_else(|| { + anyhow::format_err!( + "the crate `{dependency}` could not be found in registry index." + ) + })?; + + if config.cli_unstable().msrv_policy && honor_rust_version { + fn parse_msrv(rust_version: impl AsRef<str>) -> (u64, u64, u64) { + // HACK: `rust-version` is a subset of the `VersionReq` syntax that only ever + // has one comparator with a required minor and optional patch, and uses no + // other features. If in the future this syntax is expanded, this code will need + // to be updated. + let version_req = semver::VersionReq::parse(rust_version.as_ref()).unwrap(); + assert!(version_req.comparators.len() == 1); + let comp = &version_req.comparators[0]; + assert_eq!(comp.op, semver::Op::Caret); + assert_eq!(comp.pre, semver::Prerelease::EMPTY); + (comp.major, comp.minor.unwrap_or(0), comp.patch.unwrap_or(0)) + } + + if let Some(req_msrv) = spec.rust_version().map(parse_msrv) { + let msrvs = possibilities + .iter() + .map(|s| (s, s.rust_version().map(parse_msrv))) + .collect::<Vec<_>>(); + + // Find the latest version of the dep which has a compatible rust-version. To + // determine whether or not one rust-version is compatible with another, we + // compare the lowest possible versions they could represent, and treat + // candidates without a rust-version as compatible by default. + let (latest_msrv, _) = msrvs + .iter() + .filter(|(_, v)| v.map(|msrv| req_msrv >= msrv).unwrap_or(true)) + .last() + .ok_or_else(|| { + // Failing that, try to find the highest version with the lowest + // rust-version to report to the user. + let lowest_candidate = msrvs + .iter() + .min_set_by_key(|(_, v)| v) + .iter() + .map(|(s, _)| s) + .max_by_key(|s| s.version()); + rust_version_incompat_error( + &dependency.name, + spec.rust_version().unwrap(), + lowest_candidate.copied(), + ) + })?; + + if latest_msrv.version() < latest.version() { + config.shell().warn(format_args!( + "ignoring `{dependency}@{latest_version}` (which has a rust-version of \ + {latest_rust_version}) to satisfy this package's rust-version of \ + {rust_version} (use `--ignore-rust-version` to override)", + latest_version = latest.version(), + latest_rust_version = latest.rust_version().unwrap(), + rust_version = spec.rust_version().unwrap(), + ))?; + + latest = latest_msrv; + } + } + } + let mut dep = Dependency::from(latest); if let Some(reg_name) = dependency.registry.as_deref() { dep = dep.set_registry(reg_name); @@ -559,6 +634,31 @@ fn get_latest_dependency( } } +fn rust_version_incompat_error( + dep: &str, + rust_version: &str, + lowest_rust_version: Option<&Summary>, +) -> anyhow::Error { + let mut error_msg = format!( + "could not find version of crate `{dep}` that satisfies this package's rust-version of \ + {rust_version}\n\ + help: use `--ignore-rust-version` to override this behavior" + ); + + if let Some(lowest) = lowest_rust_version { + // rust-version must be present for this candidate since it would have been selected as + // compatible previously if it weren't. + let version = lowest.version(); + let rust_version = lowest.rust_version().unwrap(); + error_msg.push_str(&format!( + "\nnote: the lowest rust-version available for `{dep}` is {rust_version}, used in \ + version {version}" + )); + } + + anyhow::format_err!(error_msg) +} + fn select_package( dependency: &Dependency, config: &Config, diff --git a/src/tools/cargo/src/cargo/ops/cargo_clean.rs b/src/tools/cargo/src/cargo/ops/cargo_clean.rs index b3e1bf483..de3139c99 100644 --- a/src/tools/cargo/src/cargo/ops/cargo_clean.rs +++ b/src/tools/cargo/src/cargo/ops/cargo_clean.rs @@ -2,9 +2,9 @@ use crate::core::compiler::{CompileKind, CompileMode, Layout, RustcTargetData}; use crate::core::profiles::Profiles; use crate::core::{PackageIdSpec, TargetKind, Workspace}; use crate::ops; +use crate::util::edit_distance; use crate::util::errors::CargoResult; use crate::util::interning::InternedString; -use crate::util::lev_distance; use crate::util::{Config, Progress, ProgressStyle}; use anyhow::Context as _; @@ -118,7 +118,7 @@ pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> { let matches: Vec<_> = resolve.iter().filter(|id| spec.matches(*id)).collect(); if matches.is_empty() { let mut suggestion = String::new(); - suggestion.push_str(&lev_distance::closest_msg( + suggestion.push_str(&edit_distance::closest_msg( &spec.name(), resolve.iter(), |id| id.name().as_str(), diff --git a/src/tools/cargo/src/cargo/ops/cargo_install.rs b/src/tools/cargo/src/cargo/ops/cargo_install.rs index 53c3e72f7..5f843e8c7 100644 --- a/src/tools/cargo/src/cargo/ops/cargo_install.rs +++ b/src/tools/cargo/src/cargo/ops/cargo_install.rs @@ -4,7 +4,9 @@ use std::sync::Arc; use std::{env, fs}; use crate::core::compiler::{CompileKind, DefaultExecutor, Executor, UnitOutput}; -use crate::core::{Dependency, Edition, Package, PackageId, Source, SourceId, Target, Workspace}; +use crate::core::{ + Dependency, Edition, Package, PackageId, PackageIdSpec, Source, SourceId, Target, Workspace, +}; use crate::ops::{common_for_install_and_uninstall::*, FilterRule}; use crate::ops::{CompileFilter, Packages}; use crate::sources::{GitSource, PathSource, SourceConfigMap}; @@ -168,14 +170,8 @@ impl<'cfg, 'a> InstallablePackage<'cfg, 'a> { } }; - // When we build this package, we want to build the *specified* package only, - // and avoid building e.g. workspace default-members instead. Do so by constructing - // specialized compile options specific to the identified package. - // See test `path_install_workspace_root_despite_default_members`. - let mut opts = original_opts.clone(); - opts.spec = Packages::Packages(vec![pkg.name().to_string()]); - - let (ws, rustc, target) = make_ws_rustc_target(config, &opts, &source_id, pkg.clone())?; + let (ws, rustc, target) = + make_ws_rustc_target(config, &original_opts, &source_id, pkg.clone())?; // If we're installing in --locked mode and there's no `Cargo.lock` published // ie. the bin was published before https://github.com/rust-lang/cargo/pull/7026 if config.locked() && !ws.root().join("Cargo.lock").exists() { @@ -192,6 +188,17 @@ impl<'cfg, 'a> InstallablePackage<'cfg, 'a> { ws.current()?.clone() }; + // When we build this package, we want to build the *specified* package only, + // and avoid building e.g. workspace default-members instead. Do so by constructing + // specialized compile options specific to the identified package. + // See test `path_install_workspace_root_despite_default_members`. + let mut opts = original_opts.clone(); + // For cargo install tracking, we retain the source git url in `pkg`, but for the build spec + // we need to unconditionally use `ws.current()` to correctly address the path where we + // locally cloned that repo. + let pkgidspec = PackageIdSpec::from_package_id(ws.current()?.package_id()); + opts.spec = Packages::Packages(vec![pkgidspec.to_string()]); + if from_cwd { if pkg.manifest().edition() == Edition::Edition2015 { config.shell().warn( diff --git a/src/tools/cargo/src/cargo/ops/cargo_new.rs b/src/tools/cargo/src/cargo/ops/cargo_new.rs index caa1d2fa8..697798c0c 100644 --- a/src/tools/cargo/src/cargo/ops/cargo_new.rs +++ b/src/tools/cargo/src/cargo/ops/cargo_new.rs @@ -1,5 +1,6 @@ use crate::core::{Edition, Shell, Workspace}; use crate::util::errors::CargoResult; +use crate::util::important_paths::find_root_manifest_for_wd; use crate::util::{existing_vcs_repo, FossilRepo, GitRepo, HgRepo, PijulRepo}; use crate::util::{restricted_names, Config}; use anyhow::{anyhow, Context as _}; @@ -759,69 +760,72 @@ fn mk(config: &Config, opts: &MkOptions<'_>) -> CargoResult<()> { init_vcs(path, vcs, config)?; write_ignore_file(path, &ignore, vcs)?; - let mut cargotoml_path_specifier = String::new(); + // Create `Cargo.toml` file with necessary `[lib]` and `[[bin]]` sections, if needed. + let mut manifest = toml_edit::Document::new(); + manifest["package"] = toml_edit::Item::Table(toml_edit::Table::new()); + manifest["package"]["name"] = toml_edit::value(name); + manifest["package"]["version"] = toml_edit::value("0.1.0"); + let edition = match opts.edition { + Some(edition) => edition.to_string(), + None => Edition::LATEST_STABLE.to_string(), + }; + manifest["package"]["edition"] = toml_edit::value(edition); + if let Some(registry) = opts.registry { + let mut array = toml_edit::Array::default(); + array.push(registry); + manifest["package"]["publish"] = toml_edit::value(array); + } + let mut dep_table = toml_edit::Table::default(); + dep_table.decor_mut().set_prefix("\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n"); + manifest["dependencies"] = toml_edit::Item::Table(dep_table); // Calculate what `[lib]` and `[[bin]]`s we need to append to `Cargo.toml`. - for i in &opts.source_files { if i.bin { if i.relative_path != "src/main.rs" { - cargotoml_path_specifier.push_str(&format!( - r#" -[[bin]] -name = "{}" -path = {} -"#, - i.target_name, - toml::Value::String(i.relative_path.clone()) - )); + let mut bin = toml_edit::Table::new(); + bin["name"] = toml_edit::value(i.target_name.clone()); + bin["path"] = toml_edit::value(i.relative_path.clone()); + manifest["bin"] + .or_insert(toml_edit::Item::ArrayOfTables( + toml_edit::ArrayOfTables::new(), + )) + .as_array_of_tables_mut() + .expect("bin is an array of tables") + .push(bin); } } else if i.relative_path != "src/lib.rs" { - cargotoml_path_specifier.push_str(&format!( - r#" -[lib] -name = "{}" -path = {} -"#, - i.target_name, - toml::Value::String(i.relative_path.clone()) - )); + let mut lib = toml_edit::Table::new(); + lib["name"] = toml_edit::value(i.target_name.clone()); + lib["path"] = toml_edit::value(i.relative_path.clone()); + manifest["lib"] = toml_edit::Item::Table(lib); } } - // Create `Cargo.toml` file with necessary `[lib]` and `[[bin]]` sections, if needed. + let manifest_path = path.join("Cargo.toml"); + if let Ok(root_manifest_path) = find_root_manifest_for_wd(&manifest_path) { + let root_manifest = paths::read(&root_manifest_path)?; + // Sometimes the root manifest is not a valid manifest, so we only try to parse it if it is. + // This should not block the creation of the new project. It is only a best effort to + // inherit the workspace package keys. + if let Ok(workspace_document) = root_manifest.parse::<toml_edit::Document>() { + if let Some(workspace_package_keys) = workspace_document + .get("workspace") + .and_then(|workspace| workspace.get("package")) + .and_then(|package| package.as_table()) + { + update_manifest_with_inherited_workspace_package_keys( + opts, + &mut manifest, + workspace_package_keys, + ) + } + } + } - paths::write( - &path.join("Cargo.toml"), - format!( - r#"[package] -name = "{}" -version = "0.1.0" -edition = {} -{} -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -{}"#, - name, - match opts.edition { - Some(edition) => toml::Value::String(edition.to_string()), - None => toml::Value::String(Edition::LATEST_STABLE.to_string()), - }, - match opts.registry { - Some(registry) => format!( - "publish = {}\n", - toml::Value::Array(vec!(toml::Value::String(registry.to_string()))) - ), - None => "".to_string(), - }, - cargotoml_path_specifier - ) - .as_bytes(), - )?; + paths::write(&manifest_path, manifest.to_string())?; // Create all specified source files (with respective parent directories) if they don't exist. - for i in &opts.source_files { let path_of_source_file = path.join(i.relative_path.clone()); @@ -878,3 +882,40 @@ mod tests { Ok(()) } + +// Update the manifest with the inherited workspace package keys. +// If the option is not set, the key is removed from the manifest. +// If the option is set, keep the value from the manifest. +fn update_manifest_with_inherited_workspace_package_keys( + opts: &MkOptions<'_>, + manifest: &mut toml_edit::Document, + workspace_package_keys: &toml_edit::Table, +) { + if workspace_package_keys.is_empty() { + return; + } + + let try_remove_and_inherit_package_key = |key: &str, manifest: &mut toml_edit::Document| { + let package = manifest["package"] + .as_table_mut() + .expect("package is a table"); + package.remove(key); + let mut table = toml_edit::Table::new(); + table.set_dotted(true); + table["workspace"] = toml_edit::value(true); + package.insert(key, toml_edit::Item::Table(table)); + }; + + // Inherit keys from the workspace. + // Only keep the value from the manifest if the option is set. + for (key, _) in workspace_package_keys { + if key == "edition" && opts.edition.is_some() { + continue; + } + if key == "publish" && opts.registry.is_some() { + continue; + } + + try_remove_and_inherit_package_key(key, manifest); + } +} diff --git a/src/tools/cargo/src/cargo/ops/cargo_output_metadata.rs b/src/tools/cargo/src/cargo/ops/cargo_output_metadata.rs index 9d52fa09a..c0a63aa75 100644 --- a/src/tools/cargo/src/cargo/ops/cargo_output_metadata.rs +++ b/src/tools/cargo/src/cargo/ops/cargo_output_metadata.rs @@ -43,6 +43,7 @@ pub fn output_metadata(ws: &Workspace<'_>, opt: &OutputMetadataOptions) -> Cargo Ok(ExportInfo { packages, workspace_members: ws.members().map(|pkg| pkg.package_id()).collect(), + workspace_default_members: ws.default_members().map(|pkg| pkg.package_id()).collect(), resolve, target_directory: ws.target_dir().into_path_unlocked(), version: VERSION, @@ -58,6 +59,7 @@ pub fn output_metadata(ws: &Workspace<'_>, opt: &OutputMetadataOptions) -> Cargo pub struct ExportInfo { packages: Vec<SerializedPackage>, workspace_members: Vec<PackageId>, + workspace_default_members: Vec<PackageId>, resolve: Option<MetadataResolve>, target_directory: PathBuf, version: u32, diff --git a/src/tools/cargo/src/cargo/ops/cargo_package.rs b/src/tools/cargo/src/cargo/ops/cargo_package.rs index 35b213361..f80848c75 100644 --- a/src/tools/cargo/src/cargo/ops/cargo_package.rs +++ b/src/tools/cargo/src/cargo/ops/cargo_package.rs @@ -281,7 +281,7 @@ fn build_ar_list( if let Some(license_file) = &pkg.manifest().metadata().license_file { let license_path = Path::new(license_file); let abs_file_path = paths::normalize_path(&pkg.root().join(license_path)); - if abs_file_path.exists() { + if abs_file_path.is_file() { check_for_file_and_add( "license-file", license_path, @@ -291,26 +291,16 @@ fn build_ar_list( ws, )?; } else { - let rel_msg = if license_path.is_absolute() { - "".to_string() - } else { - format!(" (relative to `{}`)", pkg.root().display()) - }; - ws.config().shell().warn(&format!( - "license-file `{}` does not appear to exist{}.\n\ - Please update the license-file setting in the manifest at `{}`\n\ - This may become a hard error in the future.", - license_path.display(), - rel_msg, - pkg.manifest_path().display() - ))?; + warn_on_nonexistent_file(&pkg, &license_path, "license-file", &ws)?; } } if let Some(readme) = &pkg.manifest().metadata().readme { let readme_path = Path::new(readme); let abs_file_path = paths::normalize_path(&pkg.root().join(readme_path)); - if abs_file_path.exists() { + if abs_file_path.is_file() { check_for_file_and_add("readme", readme_path, abs_file_path, pkg, &mut result, ws)?; + } else { + warn_on_nonexistent_file(&pkg, &readme_path, "readme", &ws)?; } } result.sort_unstable_by(|a, b| a.rel_path.cmp(&b.rel_path)); @@ -342,10 +332,7 @@ fn check_for_file_and_add( Err(_) => { // The file exists somewhere outside of the package. let file_name = file_path.file_name().unwrap(); - if result - .iter() - .any(|ar| ar.rel_path.file_name().unwrap() == file_name) - { + if result.iter().any(|ar| ar.rel_path == file_name) { ws.config().shell().warn(&format!( "{} `{}` appears to be a path outside of the package, \ but there is already a file named `{}` in the root of the package. \ @@ -369,6 +356,27 @@ fn check_for_file_and_add( Ok(()) } +fn warn_on_nonexistent_file( + pkg: &Package, + path: &Path, + manifest_key_name: &'static str, + ws: &Workspace<'_>, +) -> CargoResult<()> { + let rel_msg = if path.is_absolute() { + "".to_string() + } else { + format!(" (relative to `{}`)", pkg.root().display()) + }; + ws.config().shell().warn(&format!( + "{manifest_key_name} `{}` does not appear to exist{}.\n\ + Please update the {manifest_key_name} setting in the manifest at `{}`\n\ + This may become a hard error in the future.", + path.display(), + rel_msg, + pkg.manifest_path().display() + )) +} + /// Construct `Cargo.lock` for the package to be published. fn build_lock(ws: &Workspace<'_>, orig_pkg: &Package) -> CargoResult<String> { let config = ws.config(); diff --git a/src/tools/cargo/src/cargo/ops/registry.rs b/src/tools/cargo/src/cargo/ops/registry.rs index e04f7ba2c..a8efb5492 100644 --- a/src/tools/cargo/src/cargo/ops/registry.rs +++ b/src/tools/cargo/src/cargo/ops/registry.rs @@ -35,6 +35,7 @@ use crate::util::auth::{ use crate::util::config::{Config, SslVersionConfig, SslVersionConfigRange}; use crate::util::errors::CargoResult; use crate::util::important_paths::find_root_manifest_for_wd; +use crate::util::network; use crate::util::{truncate_with_ellipsis, IntoUrl}; use crate::util::{Progress, ProgressStyle}; use crate::{drop_print, drop_println, version}; @@ -345,6 +346,7 @@ fn transmit( ref categories, ref badges, ref links, + ref rust_version, } = *manifest.metadata(); let readme_content = readme .as_ref() @@ -398,6 +400,7 @@ fn transmit( license_file: license_file.clone(), badges: badges.clone(), links: links.clone(), + rust_version: rust_version.clone(), }, tarball, ) @@ -609,16 +612,22 @@ pub fn http_handle_and_timeout(config: &Config) -> CargoResult<(Easy, HttpTimeou Ok((handle, timeout)) } +// Only use a custom transport if any HTTP options are specified, +// such as proxies or custom certificate authorities. +// +// The custom transport, however, is not as well battle-tested. pub fn needs_custom_http_transport(config: &Config) -> CargoResult<bool> { - Ok(http_proxy_exists(config)? - || *config.http_config()? != Default::default() - || config.get_env_os("HTTP_TIMEOUT").is_some()) + Ok( + network::proxy::http_proxy_exists(config.http_config()?, config) + || *config.http_config()? != Default::default() + || config.get_env_os("HTTP_TIMEOUT").is_some(), + ) } /// Configure a libcurl http handle with the defaults options for Cargo pub fn configure_http_handle(config: &Config, handle: &mut Easy) -> CargoResult<HttpTimeout> { let http = config.http_config()?; - if let Some(proxy) = http_proxy(config)? { + if let Some(proxy) = network::proxy::http_proxy(http) { handle.proxy(&proxy)?; } if let Some(cainfo) = &http.cainfo { @@ -702,12 +711,17 @@ pub fn configure_http_handle(config: &Config, handle: &mut Easy) -> CargoResult< InfoType::SslDataIn | InfoType::SslDataOut => return, _ => return, }; + let starts_with_ignore_case = |line: &str, text: &str| -> bool { + line[..line.len().min(text.len())].eq_ignore_ascii_case(text) + }; match str::from_utf8(data) { Ok(s) => { for mut line in s.lines() { - if line.starts_with("Authorization:") { + if starts_with_ignore_case(line, "authorization:") { line = "Authorization: [REDACTED]"; - } else if line[..line.len().min(10)].eq_ignore_ascii_case("set-cookie") { + } else if starts_with_ignore_case(line, "h2h3 [authorization:") { + line = "h2h3 [Authorization: [REDACTED]]"; + } else if starts_with_ignore_case(line, "set-cookie") { line = "set-cookie: [REDACTED]"; } log!(level, "http-debug: {} {}", prefix, line); @@ -766,43 +780,6 @@ impl HttpTimeout { } } -/// Finds an explicit HTTP proxy if one is available. -/// -/// Favor cargo's `http.proxy`, then git's `http.proxy`. Proxies specified -/// via environment variables are picked up by libcurl. -fn http_proxy(config: &Config) -> CargoResult<Option<String>> { - let http = config.http_config()?; - if let Some(s) = &http.proxy { - return Ok(Some(s.clone())); - } - if let Ok(cfg) = git2::Config::open_default() { - if let Ok(s) = cfg.get_string("http.proxy") { - return Ok(Some(s)); - } - } - Ok(None) -} - -/// Determine if an http proxy exists. -/// -/// Checks the following for existence, in order: -/// -/// * cargo's `http.proxy` -/// * git's `http.proxy` -/// * `http_proxy` env var -/// * `HTTP_PROXY` env var -/// * `https_proxy` env var -/// * `HTTPS_PROXY` env var -fn http_proxy_exists(config: &Config) -> CargoResult<bool> { - if http_proxy(config)?.is_some() { - Ok(true) - } else { - Ok(["http_proxy", "HTTP_PROXY", "https_proxy", "HTTPS_PROXY"] - .iter() - .any(|v| config.get_env(v).is_ok())) - } -} - pub fn registry_login( config: &Config, token: Option<Secret<&str>>, diff --git a/src/tools/cargo/src/cargo/ops/tree/graph.rs b/src/tools/cargo/src/cargo/ops/tree/graph.rs index 20a9ca0b6..d01d07f1a 100644 --- a/src/tools/cargo/src/cargo/ops/tree/graph.rs +++ b/src/tools/cargo/src/cargo/ops/tree/graph.rs @@ -362,6 +362,10 @@ fn add_pkg( if !opts.edge_kinds.contains(&EdgeKind::Dep(dep.kind())) { return false; } + // Filter out proc-macrcos if requested. + if opts.no_proc_macro && graph.package_for_id(dep_id).proc_macro() { + return false; + } if dep.is_optional() { // If the new feature resolver does not enable this // optional dep, then don't use it. diff --git a/src/tools/cargo/src/cargo/ops/tree/mod.rs b/src/tools/cargo/src/cargo/ops/tree/mod.rs index 02459f78f..f397b95af 100644 --- a/src/tools/cargo/src/cargo/ops/tree/mod.rs +++ b/src/tools/cargo/src/cargo/ops/tree/mod.rs @@ -267,7 +267,6 @@ fn print( opts.prefix, opts.no_dedupe, opts.max_display_depth, - opts.no_proc_macro, &mut visited_deps, &mut levels_continue, &mut print_stack, @@ -288,7 +287,6 @@ fn print_node<'a>( prefix: Prefix, no_dedupe: bool, max_display_depth: u32, - no_proc_macro: bool, visited_deps: &mut HashSet<usize>, levels_continue: &mut Vec<bool>, print_stack: &mut Vec<usize>, @@ -348,7 +346,6 @@ fn print_node<'a>( prefix, no_dedupe, max_display_depth, - no_proc_macro, visited_deps, levels_continue, print_stack, @@ -369,7 +366,6 @@ fn print_dependencies<'a>( prefix: Prefix, no_dedupe: bool, max_display_depth: u32, - no_proc_macro: bool, visited_deps: &mut HashSet<usize>, levels_continue: &mut Vec<bool>, print_stack: &mut Vec<usize>, @@ -406,19 +402,6 @@ fn print_dependencies<'a>( let mut it = deps .iter() .filter(|dep| { - // Filter out proc-macro dependencies. - if no_proc_macro { - match graph.node(**dep) { - &Node::Package { package_id, .. } => { - !graph.package_for_id(package_id).proc_macro() - } - _ => true, - } - } else { - true - } - }) - .filter(|dep| { // Filter out packages to prune. match graph.node(**dep) { Node::Package { package_id, .. } => { @@ -441,7 +424,6 @@ fn print_dependencies<'a>( prefix, no_dedupe, max_display_depth, - no_proc_macro, visited_deps, levels_continue, print_stack, diff --git a/src/tools/cargo/src/cargo/sources/config.rs b/src/tools/cargo/src/cargo/sources/config.rs index 97a23a0b4..5d5a4e8db 100644 --- a/src/tools/cargo/src/cargo/sources/config.rs +++ b/src/tools/cargo/src/cargo/sources/config.rs @@ -1,4 +1,4 @@ -//! Implementation of configuration for various sources +//! Implementation of configuration for various sources. //! //! This module will parse the various `source.*` TOML configuration keys into a //! structure usable by Cargo itself. Currently this is primarily used to map @@ -14,11 +14,12 @@ use log::debug; use std::collections::{HashMap, HashSet}; use url::Url; +/// Represents the entire `[source]` table in Cargo configuration. #[derive(Clone)] pub struct SourceConfigMap<'cfg> { /// Mapping of source name to the toml configuration. cfgs: HashMap<String, SourceConfig>, - /// Mapping of `SourceId` to the source name. + /// Mapping of [`SourceId`] to the source name. id2name: HashMap<SourceId, String>, config: &'cfg Config, } @@ -67,6 +68,8 @@ struct SourceConfig { } impl<'cfg> SourceConfigMap<'cfg> { + /// Like [`SourceConfigMap::empty`] but includes sources from source + /// replacement configurations. pub fn new(config: &'cfg Config) -> CargoResult<SourceConfigMap<'cfg>> { let mut base = SourceConfigMap::empty(config)?; let sources: Option<HashMap<String, SourceConfigDef>> = config.get("source")?; @@ -78,6 +81,8 @@ impl<'cfg> SourceConfigMap<'cfg> { Ok(base) } + /// Creates the default set of sources that doesn't take `[source]` + /// replacement into account. pub fn empty(config: &'cfg Config) -> CargoResult<SourceConfigMap<'cfg>> { let mut base = SourceConfigMap { cfgs: HashMap::new(), @@ -112,11 +117,14 @@ impl<'cfg> SourceConfigMap<'cfg> { Ok(base) } + /// Returns the `Config` this source config map is associated with. pub fn config(&self) -> &'cfg Config { self.config } - /// Get the `Source` for a given `SourceId`. + /// Gets the [`Source`] for a given [`SourceId`]. + /// + /// * `yanked_whitelist` --- Packages allowed to be used, even if they are yanked. pub fn load( &self, id: SourceId, @@ -208,6 +216,7 @@ restore the source replacement configuration to continue the build Ok(Box::new(ReplacedSource::new(id, new_id, new_src))) } + /// Adds a source config with an associated name. fn add(&mut self, name: &str, cfg: SourceConfig) -> CargoResult<()> { if let Some(old_name) = self.id2name.insert(cfg.id, name.to_string()) { // The user is allowed to redefine the built-in crates-io @@ -226,6 +235,7 @@ restore the source replacement configuration to continue the build Ok(()) } + /// Adds a source config from TOML definition. fn add_config(&mut self, name: String, def: SourceConfigDef) -> CargoResult<()> { let mut srcs = Vec::new(); if let Some(registry) = def.registry { diff --git a/src/tools/cargo/src/cargo/sources/directory.rs b/src/tools/cargo/src/cargo/sources/directory.rs index 46acb9f86..a527c6dd7 100644 --- a/src/tools/cargo/src/cargo/sources/directory.rs +++ b/src/tools/cargo/src/cargo/sources/directory.rs @@ -13,17 +13,64 @@ use anyhow::Context as _; use cargo_util::{paths, Sha256}; use serde::Deserialize; +/// `DirectorySource` contains a number of crates on the file system. It was +/// designed for representing vendored dependencies for `cargo vendor`. +/// +/// `DirectorySource` at this moment is just a root directory containing other +/// directories, which contain the source files of packages. Assumptions would +/// be made to determine if a directory should be included as a package of a +/// directory source's: +/// +/// * Ignore directories starting with dot `.` (tend to be hidden). +/// * Only when a `Cargo.toml` exists in a directory will it be included as +/// a package. `DirectorySource` at this time only looks at one level of +/// directories and never went deeper. +/// * There must be a [`Checksum`] file `.cargo-checksum.json` file at the same +/// level of `Cargo.toml` to ensure the integrity when a directory source was +/// created (usually by `cargo vendor`). A failure to find or parse a single +/// checksum results in a denial of loading any package in this source. +/// * Otherwise, there is no other restrction of the name of directories. At +/// this moment, it is `cargo vendor` that defines the layout and the name of +/// each directory. +/// +/// The file tree of a directory source may look like: +/// +/// ```text +/// [source root] +/// ├── a-valid-crate/ +/// │ ├── src/ +/// │ ├── .cargo-checksum.json +/// │ └── Cargo.toml +/// ├── .ignored-a-dot-crate/ +/// │ ├── src/ +/// │ ├── .cargo-checksum.json +/// │ └── Cargo.toml +/// ├── skipped-no-manifest/ +/// │ ├── src/ +/// │ └── .cargo-checksum.json +/// └── no-checksum-so-fails-the-entire-source-reading/ +/// └── Cargo.toml +/// ``` pub struct DirectorySource<'cfg> { + /// The unique identifier of this source. source_id: SourceId, + /// The root path of this source. root: PathBuf, + /// Packages that this sources has discovered. packages: HashMap<PackageId, (Package, Checksum)>, config: &'cfg Config, updated: bool, } +/// The checksum file to ensure the integrity of a package in a directory source. +/// +/// The file name is simply `.cargo-checksum.json`. The checksum algorithm as +/// of now is SHA256. #[derive(Deserialize)] struct Checksum { + /// Checksum of the package. Normally it is computed from the `.crate` file. package: Option<String>, + /// Checksums of each source file. files: HashMap<String, String>, } diff --git a/src/tools/cargo/src/cargo/sources/git/mod.rs b/src/tools/cargo/src/cargo/sources/git/mod.rs index 6c230be93..47827f267 100644 --- a/src/tools/cargo/src/cargo/sources/git/mod.rs +++ b/src/tools/cargo/src/cargo/sources/git/mod.rs @@ -6,5 +6,46 @@ mod source; mod utils; pub mod fetch { + use crate::core::features::GitoxideFeatures; + use crate::Config; + + /// The kind remote repository to fetch. + #[derive(Debug, Copy, Clone)] + pub enum RemoteKind { + /// A repository belongs to a git dependency. + GitDependency, + /// A repository belongs to a Cargo registry. + Registry, + } + + impl RemoteKind { + /// Obtain the kind of history we would want for a fetch from our remote knowing if the target repo is already shallow + /// via `repo_is_shallow` along with gitoxide-specific feature configuration via `config`. + /// `rev_and_ref` is additional information that affects whether or not we may be shallow. + pub(crate) fn to_shallow_setting( + &self, + repo_is_shallow: bool, + config: &Config, + ) -> gix::remote::fetch::Shallow { + let has_feature = |cb: &dyn Fn(GitoxideFeatures) -> bool| { + config + .cli_unstable() + .gitoxide + .map_or(false, |features| cb(features)) + }; + + // maintain shallow-ness and keep downloading single commits, or see if we can do shallow clones + if !repo_is_shallow { + match self { + RemoteKind::GitDependency if has_feature(&|git| git.shallow_deps) => {} + RemoteKind::Registry if has_feature(&|git| git.shallow_index) => {} + _ => return gix::remote::fetch::Shallow::NoChange, + } + }; + + gix::remote::fetch::Shallow::DepthAtRemote(1.try_into().expect("non-zero")) + } + } + pub type Error = gix::env::collate::fetch::Error<gix::refspec::parse::Error>; } diff --git a/src/tools/cargo/src/cargo/sources/git/oxide.rs b/src/tools/cargo/src/cargo/sources/git/oxide.rs index 0270579da..c8d0a4ecd 100644 --- a/src/tools/cargo/src/cargo/sources/git/oxide.rs +++ b/src/tools/cargo/src/cargo/sources/git/oxide.rs @@ -29,6 +29,10 @@ pub fn with_retry_and_progress( ) -> CargoResult<()> { std::thread::scope(|s| { let mut progress_bar = Progress::new("Fetch", config); + let is_shallow = config + .cli_unstable() + .gitoxide + .map_or(false, |gix| gix.shallow_deps || gix.shallow_index); network::retry::with_retry(config, || { let progress_root: Arc<gix::progress::tree::Root> = gix::progress::tree::root::Options { @@ -50,7 +54,7 @@ pub fn with_retry_and_progress( ); amend_authentication_hints(res, urls.get_mut().take()) }); - translate_progress_to_bar(&mut progress_bar, root)?; + translate_progress_to_bar(&mut progress_bar, root, is_shallow)?; thread.join().expect("no panic in scoped thread") }) }) @@ -59,7 +63,9 @@ pub fn with_retry_and_progress( fn translate_progress_to_bar( progress_bar: &mut Progress<'_>, root: Weak<gix::progress::tree::Root>, + is_shallow: bool, ) -> CargoResult<()> { + let remote_progress: gix::progress::Id = gix::remote::fetch::ProgressId::RemoteProgress.into(); let read_pack_bytes: gix::progress::Id = gix::odb::pack::bundle::write::ProgressId::ReadPackBytes.into(); let delta_index_objects: gix::progress::Id = @@ -88,6 +94,7 @@ fn translate_progress_to_bar( "progress should be smoother by keeping these as multiples of each other" ); + let num_phases = if is_shallow { 3 } else { 2 }; // indexing + delta-resolution, both with same amount of objects to handle while let Some(root) = root.upgrade() { std::thread::sleep(sleep_interval); let needs_update = last_fast_update.elapsed() >= fast_check_interval; @@ -102,31 +109,37 @@ fn translate_progress_to_bar( fn progress_by_id( id: gix::progress::Id, task: &gix::progress::Task, - ) -> Option<&gix::progress::Value> { - (task.id == id).then(|| task.progress.as_ref()).flatten() + ) -> Option<(&str, &gix::progress::Value)> { + (task.id == id) + .then(|| task.progress.as_ref()) + .flatten() + .map(|value| (task.name.as_str(), value)) } fn find_in<K>( tasks: &[(K, gix::progress::Task)], - cb: impl Fn(&gix::progress::Task) -> Option<&gix::progress::Value>, - ) -> Option<&gix::progress::Value> { + cb: impl Fn(&gix::progress::Task) -> Option<(&str, &gix::progress::Value)>, + ) -> Option<(&str, &gix::progress::Value)> { tasks.iter().find_map(|(_, t)| cb(t)) } - const NUM_PHASES: usize = 2; // indexing + delta-resolution, both with same amount of objects to handle - if let Some(objs) = find_in(&tasks, |t| progress_by_id(resolve_objects, t)) { - // Resolving deltas. + if let Some((_, objs)) = find_in(&tasks, |t| progress_by_id(resolve_objects, t)) { + // Phase 3: Resolving deltas. let objects = objs.step.load(Ordering::Relaxed); let total_objects = objs.done_at.expect("known amount of objects"); let msg = format!(", ({objects}/{total_objects}) resolving deltas"); - progress_bar.tick(total_objects + objects, total_objects * NUM_PHASES, &msg)?; + progress_bar.tick( + (total_objects * (num_phases - 1)) + objects, + total_objects * num_phases, + &msg, + )?; } else if let Some((objs, read_pack)) = find_in(&tasks, |t| progress_by_id(read_pack_bytes, t)).and_then(|read| { find_in(&tasks, |t| progress_by_id(delta_index_objects, t)) - .map(|delta| (delta, read)) + .map(|delta| (delta.1, read.1)) }) { - // Receiving objects. + // Phase 2: Receiving objects. let objects = objs.step.load(Ordering::Relaxed); let total_objects = objs.done_at.expect("known amount of objects"); let received_bytes = read_pack.step.load(Ordering::Relaxed); @@ -139,7 +152,25 @@ fn translate_progress_to_bar( let (rate, unit) = human_readable_bytes(counter.rate() as u64); let msg = format!(", {rate:.2}{unit}/s"); - progress_bar.tick(objects, total_objects * NUM_PHASES, &msg)?; + progress_bar.tick( + (total_objects * (num_phases - 2)) + objects, + total_objects * num_phases, + &msg, + )?; + } else if let Some((action, remote)) = + find_in(&tasks, |t| progress_by_id(remote_progress, t)) + { + if !is_shallow { + continue; + } + // phase 1: work on the remote side + + // Resolving deltas. + let objects = remote.step.load(Ordering::Relaxed); + if let Some(total_objects) = remote.done_at { + let msg = format!(", ({objects}/{total_objects}) {action}"); + progress_bar.tick(objects, total_objects * num_phases, &msg)?; + } } } Ok(()) @@ -232,7 +263,7 @@ pub fn open_repo( ) -> Result<gix::Repository, gix::open::Error> { gix::open_opts(repo_path, { let mut opts = gix::open::Options::default(); - opts.permissions.config = gix::permissions::Config::all(); + opts.permissions.config = gix::open::permissions::Config::all(); opts.permissions.config.git_binary = purpose.needs_git_binary_config(); opts.with(gix::sec::Trust::Full) .config_overrides(config_overrides) diff --git a/src/tools/cargo/src/cargo/sources/git/source.rs b/src/tools/cargo/src/cargo/sources/git/source.rs index 90c47093d..4cdb8983b 100644 --- a/src/tools/cargo/src/cargo/sources/git/source.rs +++ b/src/tools/cargo/src/cargo/sources/git/source.rs @@ -29,17 +29,26 @@ impl<'cfg> GitSource<'cfg> { assert!(source_id.is_git(), "id is not git, id={}", source_id); let remote = GitRemote::new(source_id.url()); - let ident = ident(&source_id); - - let source = GitSource { - remote, - manifest_reference: source_id.git_reference().unwrap().clone(), - locked_rev: match source_id.precise() { + let manifest_reference = source_id.git_reference().unwrap().clone(); + let locked_rev = + match source_id.precise() { Some(s) => Some(git2::Oid::from_str(s).with_context(|| { format!("precise value for git is not a git revision: {}", s) })?), None => None, - }, + }; + let ident = ident_shallow( + &source_id, + config + .cli_unstable() + .gitoxide + .map_or(false, |gix| gix.fetch && gix.shallow_deps), + ); + + let source = GitSource { + remote, + manifest_reference, + locked_rev, source_id, path_source: None, ident, @@ -63,6 +72,7 @@ impl<'cfg> GitSource<'cfg> { } } +/// Create an identifier from a URL, essentially turning `proto://host/path/repo` into `repo-<hash-of-url>`. fn ident(id: &SourceId) -> String { let ident = id .canonical_url() @@ -76,6 +86,18 @@ fn ident(id: &SourceId) -> String { format!("{}-{}", ident, short_hash(id.canonical_url())) } +/// Like `ident()`, but appends `-shallow` to it, turning `proto://host/path/repo` into `repo-<hash-of-url>-shallow`. +/// +/// It's important to separate shallow from non-shallow clones for reasons of backwards compatibility - older +/// cargo's aren't necessarily handling shallow clones correctly. +fn ident_shallow(id: &SourceId, is_shallow: bool) -> String { + let mut ident = ident(id); + if is_shallow { + ident.push_str("-shallow"); + } + ident +} + impl<'cfg> Debug for GitSource<'cfg> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "git repo at {}", self.remote.url())?; diff --git a/src/tools/cargo/src/cargo/sources/git/utils.rs b/src/tools/cargo/src/cargo/sources/git/utils.rs index a7ffccf79..c14d1daf3 100644 --- a/src/tools/cargo/src/cargo/sources/git/utils.rs +++ b/src/tools/cargo/src/cargo/sources/git/utils.rs @@ -2,6 +2,7 @@ //! authentication/cloning. use crate::core::{GitReference, Verbosity}; +use crate::sources::git::fetch::RemoteKind; use crate::sources::git::oxide; use crate::sources::git::oxide::cargo_config_to_gitoxide_overrides; use crate::util::errors::CargoResult; @@ -96,20 +97,24 @@ impl GitRemote { // if we can. If that can successfully load our revision then we've // populated the database with the latest version of `reference`, so // return that database and the rev we resolve to. + let locked_ref = locked_rev.map(|oid| GitReference::Rev(oid.to_string())); + let reference = locked_ref.as_ref().unwrap_or(reference); if let Some(mut db) = db { - fetch(&mut db.repo, self.url.as_str(), reference, cargo_config) - .context(format!("failed to fetch into: {}", into.display()))?; - match locked_rev { - Some(rev) => { - if db.contains(rev) { - return Ok((db, rev)); - } - } - None => { - if let Ok(rev) = reference.resolve(&db.repo) { - return Ok((db, rev)); - } - } + fetch( + &mut db.repo, + self.url.as_str(), + reference, + cargo_config, + RemoteKind::GitDependency, + ) + .with_context(|| format!("failed to fetch into: {}", into.display()))?; + + let resolved_commit_hash = match locked_rev { + Some(rev) => db.contains(rev).then_some(rev), + None => reference.resolve(&db.repo).ok(), + }; + if let Some(rev) = resolved_commit_hash { + return Ok((db, rev)); } } @@ -121,8 +126,14 @@ impl GitRemote { } paths::create_dir_all(into)?; let mut repo = init(into, true)?; - fetch(&mut repo, self.url.as_str(), reference, cargo_config) - .context(format!("failed to clone into: {}", into.display()))?; + fetch( + &mut repo, + self.url.as_str(), + reference, + cargo_config, + RemoteKind::GitDependency, + ) + .with_context(|| format!("failed to clone into: {}", into.display()))?; let rev = match locked_rev { Some(rev) => rev, None => reference.resolve(&repo)?, @@ -282,6 +293,16 @@ impl<'a> GitCheckout<'a> { .with_checkout(checkout) .fetch_options(fopts) .clone(url.as_str(), into)?; + // `git2` doesn't seem to handle shallow repos correctly when doing a local clone. + // Fortunately all that's needed is the copy of the one file that defines the + // shallow boundary, the commits which have their parents omitted as part of the + // shallow clone. + if database.repo.is_shallow() { + std::fs::copy( + database.repo.path().join("shallow"), + r.path().join("shallow"), + )?; + } repo = Some(r); Ok(()) })?; @@ -432,7 +453,14 @@ impl<'a> GitCheckout<'a> { cargo_config .shell() .status("Updating", format!("git submodule `{}`", url))?; - fetch(&mut repo, &url, &reference, cargo_config).with_context(|| { + fetch( + &mut repo, + &url, + &reference, + cargo_config, + RemoteKind::GitDependency, + ) + .with_context(|| { format!( "failed to fetch submodule `{}` from {}", child.name().unwrap_or(""), @@ -803,11 +831,15 @@ pub fn with_fetch_options( }) } +/// Note that `history` is a complex computed value to determine whether it's acceptable to perform shallow clones +/// at all. It's needed to allow the caller to determine the correct position of the destination repository or move it +/// into place should its position change. pub fn fetch( repo: &mut git2::Repository, orig_url: &str, reference: &GitReference, config: &Config, + remote_kind: RemoteKind, ) -> CargoResult<()> { if config.frozen() { anyhow::bail!( @@ -819,8 +851,10 @@ pub fn fetch( anyhow::bail!("can't update a git repository in the offline mode") } + let shallow = remote_kind.to_shallow_setting(repo.is_shallow(), config); + // If we're fetching from GitHub, attempt GitHub's special fast path for - // testing if we've already got an up-to-date copy of the repository + // testing if we've already got an up-to-date copy of the repository. let oid_to_fetch = match github_fast_path(repo, orig_url, reference, config) { Ok(FastPathRev::UpToDate) => return Ok(()), Ok(FastPathRev::NeedsFetch(rev)) => Some(rev), @@ -852,6 +886,7 @@ pub fn fetch( GitReference::Branch(b) => { refspecs.push(format!("+refs/heads/{0}:refs/remotes/origin/{0}", b)); } + GitReference::Tag(t) => { refspecs.push(format!("+refs/tags/{0}:refs/remotes/origin/tags/{0}", t)); } @@ -865,6 +900,16 @@ pub fn fetch( refspecs.push(format!("+{0}:{0}", rev)); } else if let Some(oid_to_fetch) = oid_to_fetch { refspecs.push(format!("+{0}:refs/commit/{0}", oid_to_fetch)); + } else if !matches!(shallow, gix::remote::fetch::Shallow::NoChange) + && rev.parse::<Oid>().is_ok() + { + // There is a specific commit to fetch and we will do so in shallow-mode only + // to not disturb the previous logic. + // Note that with typical settings for shallowing, we will just fetch a single `rev` + // as single commit. + // The reason we write to `refs/remotes/origin/HEAD` is that it's of special significance + // when during `GitReference::resolve()`, but otherwise it shouldn't matter. + refspecs.push(format!("+{0}:refs/remotes/origin/HEAD", rev)); } else { // We don't know what the rev will point to. To handle this // situation we fetch all branches and tags, and then we pray @@ -936,8 +981,7 @@ pub fn fetch( .url(gix::remote::Direction::Fetch) .expect("set at init") .to_owned(); - let connection = - remote.connect(gix::remote::Direction::Fetch, &mut progress)?; + let connection = remote.connect(gix::remote::Direction::Fetch)?; let mut authenticate = connection.configured_credentials(url)?; let connection = connection.with_credentials( move |action: gix::protocol::credentials::helper::Action| { @@ -951,8 +995,9 @@ pub fn fetch( }, ); let outcome = connection - .prepare_fetch(gix::remote::ref_map::Options::default())? - .receive(should_interrupt)?; + .prepare_fetch(&mut progress, gix::remote::ref_map::Options::default())? + .with_shallow(shallow.clone().into()) + .receive(&mut progress, should_interrupt)?; Ok(outcome) }); let err = match res { @@ -967,6 +1012,7 @@ pub fn fetch( // folder before writing files into it, or else not even open a directory as git repository (which is // also handled here). && err.is_corrupted() + || has_shallow_lock_file(&err) { repo_reinitialized.store(true, Ordering::Relaxed); debug!( @@ -1036,6 +1082,17 @@ pub fn fetch( } } +/// `gitoxide` uses shallow locks to assure consistency when fetching to and to avoid races, and to write +/// files atomically. +/// Cargo has its own lock files and doesn't need that mechanism for race protection, so a stray lock means +/// a signal interrupted a previous shallow fetch and doesn't mean a race is happening. +fn has_shallow_lock_file(err: &crate::sources::git::fetch::Error) -> bool { + matches!( + err, + gix::env::collate::fetch::Error::Fetch(gix::remote::fetch::Error::LockShallowFile(_)) + ) +} + fn fetch_with_cli( repo: &mut git2::Repository, url: &str, diff --git a/src/tools/cargo/src/cargo/sources/mod.rs b/src/tools/cargo/src/cargo/sources/mod.rs index 7d238d47d..81eda24ca 100644 --- a/src/tools/cargo/src/cargo/sources/mod.rs +++ b/src/tools/cargo/src/cargo/sources/mod.rs @@ -1,3 +1,24 @@ +//! Implementations of `Source` trait. +//! +//! Cargo provides several built-in implementations of [`Source`] trait. Namely, +//! +//! * [`RegistrySource`] --- A source that provides an index for people to query +//! a crate's metadata, and fetch files for a certain crate. crates.io falls +//! into this category. So do local registry and sparse registry. +//! * [`DirectorySource`] --- Files are downloaded ahead of time. Primarily +//! designed for crates generated from `cargo vendor`. +//! * [`GitSource`] --- This gets crate information from a git repository. +//! * [`PathSource`] --- This gets crate information from a local path on the +//! filesystem. +//! * [`ReplacedSource`] --- This manages the [source replacement] feature, +//! redirecting operations on the original source to the replacement. +//! +//! This module also contains [`SourceConfigMap`], which is effectively the +//! representation of the `[source.*]` value in Cargo configuration. +//! +//! [`Source`]: crate::core::Source +//! [source replacement]: https://doc.rust-lang.org/nightly/cargo/reference/source-replacement.html + pub use self::config::SourceConfigMap; pub use self::directory::DirectorySource; pub use self::git::GitSource; diff --git a/src/tools/cargo/src/cargo/sources/path.rs b/src/tools/cargo/src/cargo/sources/path.rs index 37e1e1f0f..2f147b19e 100644 --- a/src/tools/cargo/src/cargo/sources/path.rs +++ b/src/tools/cargo/src/cargo/sources/path.rs @@ -14,13 +14,28 @@ use ignore::gitignore::GitignoreBuilder; use log::{trace, warn}; use walkdir::WalkDir; +/// A source represents one or multiple packages gathering from a given root +/// path on the filesystem. +/// +/// It's the cornerstone of every other source --- other implementations +/// eventually need to call `PathSource` to read local packages somewhere on +/// the filesystem. +/// +/// It also provides convenient methods like [`PathSource::list_files`] to +/// list all files in a package, given its ability to walk the filesystem. pub struct PathSource<'cfg> { + /// The unique identifier of this source. source_id: SourceId, + /// The root path of this source. path: PathBuf, + /// Whether this source has updated all package informations it may contain. updated: bool, + /// Packages that this sources has discovered. packages: Vec<Package>, - config: &'cfg Config, + /// Whether this source should discover nested packages recursively. + /// See [`PathSource::new_recursive`] for more. recursive: bool, + config: &'cfg Config, } impl<'cfg> PathSource<'cfg> { @@ -41,9 +56,9 @@ impl<'cfg> PathSource<'cfg> { /// Creates a new source which is walked recursively to discover packages. /// - /// This is similar to the `new` method except that instead of requiring a - /// valid package to be present at `root` the folder is walked entirely to - /// crawl for packages. + /// This is similar to the [`PathSource::new`] method except that instead + /// of requiring a valid package to be present at `root` the folder is + /// walked entirely to crawl for packages. /// /// Note that this should be used with care and likely shouldn't be chosen /// by default! @@ -54,6 +69,8 @@ impl<'cfg> PathSource<'cfg> { } } + /// Preloads a package for this source. The source is assumed that it has + /// yet loaded any other packages. pub fn preload_with(&mut self, pkg: Package) { assert!(!self.updated); assert!(!self.recursive); @@ -62,6 +79,7 @@ impl<'cfg> PathSource<'cfg> { self.packages.push(pkg); } + /// Gets the package on the root path. pub fn root_package(&mut self) -> CargoResult<Package> { trace!("root_package; source={:?}", self); @@ -76,6 +94,8 @@ impl<'cfg> PathSource<'cfg> { } } + /// Returns the packages discovered by this source. It may walk the + /// the filesystem if package informations haven't yet updated. pub fn read_packages(&self) -> CargoResult<Vec<Package>> { if self.updated { Ok(self.packages.clone()) @@ -96,7 +116,8 @@ impl<'cfg> PathSource<'cfg> { /// /// The basic assumption of this method is that all files in the directory /// are relevant for building this package, but it also contains logic to - /// use other methods like .gitignore to filter the list of files. + /// use other methods like `.gitignore`, `package.include`, or + /// `package.exclude` to filter the list of files. pub fn list_files(&self, pkg: &Package) -> CargoResult<Vec<PathBuf>> { self._list_files(pkg).with_context(|| { format!( @@ -106,6 +127,7 @@ impl<'cfg> PathSource<'cfg> { }) } + /// See [`PathSource::list_files`]. fn _list_files(&self, pkg: &Package) -> CargoResult<Vec<PathBuf>> { let root = pkg.root(); let no_include_option = pkg.manifest().include().is_empty(); @@ -218,6 +240,11 @@ impl<'cfg> PathSource<'cfg> { Ok(None) } + /// Lists files relevant to building this package inside this source by + /// consulting both Git index (tracked) or status (untracked) under + /// a given Git repository. + /// + /// This looks into Git submodules as well. fn list_files_git( &self, pkg: &Package, @@ -373,6 +400,11 @@ impl<'cfg> PathSource<'cfg> { } } + /// Lists files relevant to building this package inside this source by + /// walking the filesystem from the package root path. + /// + /// This is a fallback for [`PathSource::list_files_git`] when the package + /// is not tracked under a Git repository. fn list_files_walk( &self, pkg: &Package, @@ -383,6 +415,7 @@ impl<'cfg> PathSource<'cfg> { Ok(ret) } + /// Helper recursive function for [`PathSource::list_files_walk`]. fn walk( &self, path: &Path, @@ -448,6 +481,7 @@ impl<'cfg> PathSource<'cfg> { Ok(()) } + /// Gets the last modified file in a package. pub fn last_modified_file(&self, pkg: &Package) -> CargoResult<(FileTime, PathBuf)> { if !self.updated { return Err(internal(format!( @@ -479,10 +513,12 @@ impl<'cfg> PathSource<'cfg> { Ok((max, max_path)) } + /// Returns the root path of this source. pub fn path(&self) -> &Path { &self.path } + /// Discovers packages inside this source if it hasn't yet done. pub fn update(&mut self) -> CargoResult<()> { if !self.updated { let packages = self.read_packages()?; diff --git a/src/tools/cargo/src/cargo/sources/registry/index.rs b/src/tools/cargo/src/cargo/sources/registry/index.rs index a21511434..d857a053e 100644 --- a/src/tools/cargo/src/cargo/sources/registry/index.rs +++ b/src/tools/cargo/src/cargo/sources/registry/index.rs @@ -81,91 +81,6 @@ use std::path::Path; use std::str; use std::task::{ready, Poll}; -/// Crates.io treats hyphen and underscores as interchangeable, but the index and old Cargo do not. -/// Therefore, the index must store uncanonicalized version of the name so old Cargo's can find it. -/// This loop tries all possible combinations of switching hyphen and underscores to find the -/// uncanonicalized one. As all stored inputs have the correct spelling, we start with the spelling -/// as-provided. -pub struct UncanonicalizedIter<'s> { - input: &'s str, - num_hyphen_underscore: u32, - hyphen_combination_num: u16, -} - -impl<'s> UncanonicalizedIter<'s> { - pub fn new(input: &'s str) -> Self { - let num_hyphen_underscore = input.chars().filter(|&c| c == '_' || c == '-').count() as u32; - UncanonicalizedIter { - input, - num_hyphen_underscore, - hyphen_combination_num: 0, - } - } -} - -impl<'s> Iterator for UncanonicalizedIter<'s> { - type Item = String; - - fn next(&mut self) -> Option<Self::Item> { - if self.hyphen_combination_num > 0 - && self.hyphen_combination_num.trailing_zeros() >= self.num_hyphen_underscore - { - return None; - } - - let ret = Some( - self.input - .chars() - .scan(0u16, |s, c| { - // the check against 15 here's to prevent - // shift overflow on inputs with more than 15 hyphens - if (c == '_' || c == '-') && *s <= 15 { - let switch = (self.hyphen_combination_num & (1u16 << *s)) > 0; - let out = if (c == '_') ^ switch { '_' } else { '-' }; - *s += 1; - Some(out) - } else { - Some(c) - } - }) - .collect(), - ); - self.hyphen_combination_num += 1; - ret - } -} - -#[test] -fn no_hyphen() { - assert_eq!( - UncanonicalizedIter::new("test").collect::<Vec<_>>(), - vec!["test".to_string()] - ) -} - -#[test] -fn two_hyphen() { - assert_eq!( - UncanonicalizedIter::new("te-_st").collect::<Vec<_>>(), - vec![ - "te-_st".to_string(), - "te__st".to_string(), - "te--st".to_string(), - "te_-st".to_string() - ] - ) -} - -#[test] -fn overflow_hyphen() { - assert_eq!( - UncanonicalizedIter::new("te-_-_-_-_-_-_-_-_-st") - .take(100) - .count(), - 100 - ) -} - /// Manager for handling the on-disk index. /// /// Note that local and remote registries store the index differently. Local @@ -814,6 +729,7 @@ impl IndexSummary { features2, yanked, links, + rust_version, v, } = serde_json::from_slice(line)?; let v = v.unwrap_or(1); @@ -828,7 +744,7 @@ impl IndexSummary { features.entry(name).or_default().extend(values); } } - let mut summary = Summary::new(config, pkgid, deps, &features, links)?; + let mut summary = Summary::new(config, pkgid, deps, &features, links, rust_version)?; summary.set_checksum(cksum); Ok(IndexSummary { summary, diff --git a/src/tools/cargo/src/cargo/sources/registry/mod.rs b/src/tools/cargo/src/cargo/sources/registry/mod.rs index aa3f5dc5f..c76ee6142 100644 --- a/src/tools/cargo/src/cargo/sources/registry/mod.rs +++ b/src/tools/cargo/src/cargo/sources/registry/mod.rs @@ -161,8 +161,11 @@ use std::borrow::Cow; use std::collections::BTreeMap; use std::collections::HashSet; +use std::fs; use std::fs::{File, OpenOptions}; -use std::io::{self, Write}; +use std::io; +use std::io::Read; +use std::io::Write; use std::path::{Path, PathBuf}; use std::task::{ready, Poll}; @@ -172,6 +175,7 @@ use flate2::read::GzDecoder; use log::debug; use semver::Version; use serde::Deserialize; +use serde::Serialize; use tar::Archive; use crate::core::dependency::{DepKind, Dependency}; @@ -199,6 +203,14 @@ const CHECKSUM_TEMPLATE: &str = "{sha256-checksum}"; const MAX_UNPACK_SIZE: u64 = 512 * 1024 * 1024; const MAX_COMPRESSION_RATIO: usize = 20; // 20:1 +/// The content inside `.cargo-ok`. +/// See [`RegistrySource::unpack_package`] for more. +#[derive(Deserialize, Serialize)] +struct LockMetadata { + /// The version of `.cargo-ok` file + v: u32, +} + /// A "source" for a local (see `local::LocalRegistry`) or remote (see /// `remote::RemoteRegistry`) registry. /// @@ -241,7 +253,7 @@ pub struct RegistryConfig { /// crate's sha256 checksum. /// /// For backwards compatibility, if the string does not contain any - /// markers (`{crate}`, `{version}`, `{prefix}`, or ``{lowerprefix}`), it + /// markers (`{crate}`, `{version}`, `{prefix}`, or `{lowerprefix}`), it /// will be extended with `/{crate}/{version}/download` to /// support registries like crates.io which were created before the /// templating setup was created. @@ -287,6 +299,13 @@ pub struct RegistryPackage<'a> { /// Added early 2018 (see <https://github.com/rust-lang/cargo/pull/4978>), /// can be `None` if published before then. links: Option<InternedString>, + /// Required version of rust + /// + /// Corresponds to `package.rust-version`. + /// + /// Added in 2023 (see <https://github.com/rust-lang/crates.io/pull/6267>), + /// can be `None` if published before then or if not set in the manifest. + rust_version: Option<InternedString>, /// The schema version for this entry. /// /// If this is None, it defaults to version 1. Entries with unknown @@ -549,10 +568,14 @@ mod index; mod local; mod remote; -fn short_name(id: SourceId) -> String { +fn short_name(id: SourceId, is_shallow: bool) -> String { let hash = hex::short_hash(&id); let ident = id.url().host_str().unwrap_or("").to_string(); - format!("{}-{}", ident, hash) + let mut name = format!("{}-{}", ident, hash); + if is_shallow { + name.push_str("-shallow"); + } + name } impl<'cfg> RegistrySource<'cfg> { @@ -562,7 +585,14 @@ impl<'cfg> RegistrySource<'cfg> { config: &'cfg Config, ) -> CargoResult<RegistrySource<'cfg>> { assert!(source_id.is_remote_registry()); - let name = short_name(source_id); + let name = short_name( + source_id, + config + .cli_unstable() + .gitoxide + .map_or(false, |gix| gix.fetch && gix.shallow_index) + && !source_id.is_sparse(), + ); let ops = if source_id.is_sparse() { Box::new(http_remote::HttpRegistry::new(source_id, config, &name)?) as Box<_> } else { @@ -584,7 +614,7 @@ impl<'cfg> RegistrySource<'cfg> { yanked_whitelist: &HashSet<PackageId>, config: &'cfg Config, ) -> RegistrySource<'cfg> { - let name = short_name(source_id); + let name = short_name(source_id, false); let ops = local::LocalRegistry::new(path, config, &name); RegistrySource::new(source_id, config, &name, Box::new(ops), yanked_whitelist) } @@ -617,6 +647,50 @@ impl<'cfg> RegistrySource<'cfg> { /// compiled. /// /// No action is taken if the source looks like it's already unpacked. + /// + /// # History of interruption detection with `.cargo-ok` file + /// + /// Cargo has always included a `.cargo-ok` file ([`PACKAGE_SOURCE_LOCK`]) + /// to detect if extraction was interrupted, but it was originally empty. + /// + /// In 1.34, Cargo was changed to create the `.cargo-ok` file before it + /// started extraction to implement fine-grained locking. After it was + /// finished extracting, it wrote two bytes to indicate it was complete. + /// It would use the length check to detect if it was possibly interrupted. + /// + /// In 1.36, Cargo changed to not use fine-grained locking, and instead used + /// a global lock. The use of `.cargo-ok` was no longer needed for locking + /// purposes, but was kept to detect when extraction was interrupted. + /// + /// In 1.49, Cargo changed to not create the `.cargo-ok` file before it + /// started extraction to deal with `.crate` files that inexplicably had + /// a `.cargo-ok` file in them. + /// + /// In 1.64, Cargo changed to detect `.crate` files with `.cargo-ok` files + /// in them in response to [CVE-2022-36113], which dealt with malicious + /// `.crate` files making `.cargo-ok` a symlink causing cargo to write "ok" + /// to any arbitrary file on the filesystem it has permission to. + /// + /// In 1.71, `.cargo-ok` changed to contain a JSON `{ v: 1 }` to indicate + /// the version of it. A failure of parsing will result in a heavy-hammer + /// approach that unpacks the `.crate` file again. This is in response to a + /// security issue that the unpacking didn't respect umask on Unix systems. + /// + /// This is all a long-winded way of explaining the circumstances that might + /// cause a directory to contain a `.cargo-ok` file that is empty or + /// otherwise corrupted. Either this was extracted by a version of Rust + /// before 1.34, in which case everything should be fine. However, an empty + /// file created by versions 1.36 to 1.49 indicates that the extraction was + /// interrupted and that we need to start again. + /// + /// Another possibility is that the filesystem is simply corrupted, in + /// which case deleting the directory might be the safe thing to do. That + /// is probably unlikely, though. + /// + /// To be safe, we deletes the directory and starts over again if an empty + /// `.cargo-ok` file is found. + /// + /// [CVE-2022-36113]: https://blog.rust-lang.org/2022/09/14/cargo-cves.html#arbitrary-file-corruption-cve-2022-36113 fn unpack_package(&self, pkg: PackageId, tarball: &File) -> CargoResult<PathBuf> { // The `.cargo-ok` file is used to track if the source is already // unpacked. @@ -625,62 +699,32 @@ impl<'cfg> RegistrySource<'cfg> { let path = dst.join(PACKAGE_SOURCE_LOCK); let path = self.config.assert_package_cache_locked(&path); let unpack_dir = path.parent().unwrap(); - match path.metadata() { - Ok(meta) if meta.len() > 0 => return Ok(unpack_dir.to_path_buf()), - Ok(_meta) => { - // The `.cargo-ok` file is not in a state we expect it to be - // (with two bytes containing "ok"). - // - // Cargo has always included a `.cargo-ok` file to detect if - // extraction was interrupted, but it was originally empty. - // - // In 1.34, Cargo was changed to create the `.cargo-ok` file - // before it started extraction to implement fine-grained - // locking. After it was finished extracting, it wrote two - // bytes to indicate it was complete. It would use the length - // check to detect if it was possibly interrupted. - // - // In 1.36, Cargo changed to not use fine-grained locking, and - // instead used a global lock. The use of `.cargo-ok` was no - // longer needed for locking purposes, but was kept to detect - // when extraction was interrupted. - // - // In 1.49, Cargo changed to not create the `.cargo-ok` file - // before it started extraction to deal with `.crate` files - // that inexplicably had a `.cargo-ok` file in them. - // - // In 1.64, Cargo changed to detect `.crate` files with - // `.cargo-ok` files in them in response to CVE-2022-36113, - // which dealt with malicious `.crate` files making - // `.cargo-ok` a symlink causing cargo to write "ok" to any - // arbitrary file on the filesystem it has permission to. - // - // This is all a long-winded way of explaining the - // circumstances that might cause a directory to contain a - // `.cargo-ok` file that is empty or otherwise corrupted. - // Either this was extracted by a version of Rust before 1.34, - // in which case everything should be fine. However, an empty - // file created by versions 1.36 to 1.49 indicates that the - // extraction was interrupted and that we need to start again. - // - // Another possibility is that the filesystem is simply - // corrupted, in which case deleting the directory might be - // the safe thing to do. That is probably unlikely, though. - // - // To be safe, this deletes the directory and starts over - // again. - log::warn!("unexpected length of {path:?}, clearing cache"); - paths::remove_dir_all(dst.as_path_unlocked())?; - } + match fs::read_to_string(path) { + Ok(ok) => match serde_json::from_str::<LockMetadata>(&ok) { + Ok(lock_meta) if lock_meta.v == 1 => { + return Ok(unpack_dir.to_path_buf()); + } + _ => { + if ok == "ok" { + log::debug!("old `ok` content found, clearing cache"); + } else { + log::warn!("unrecognized .cargo-ok content, clearing cache: {ok}"); + } + // See comment of `unpack_package` about why removing all stuff. + paths::remove_dir_all(dst.as_path_unlocked())?; + } + }, Err(e) if e.kind() == io::ErrorKind::NotFound => {} - Err(e) => anyhow::bail!("failed to access package completion {path:?}: {e}"), + Err(e) => anyhow::bail!("unable to read .cargo-ok file at {path:?}: {e}"), } dst.create_dir()?; let mut tar = { let size_limit = max_unpack_size(self.config, tarball.metadata()?.len()); let gz = GzDecoder::new(tarball); let gz = LimitErrorReader::new(gz, size_limit); - Archive::new(gz) + let mut tar = Archive::new(gz); + set_mask(&mut tar); + tar }; let prefix = unpack_dir.file_name().unwrap(); let parent = unpack_dir.parent().unwrap(); @@ -735,7 +779,9 @@ impl<'cfg> RegistrySource<'cfg> { .write(true) .open(&path) .with_context(|| format!("failed to open `{}`", path.display()))?; - write!(ok, "ok")?; + + let lock_meta = LockMetadata { v: 1 }; + write!(ok, "{}", serde_json::to_string(&lock_meta).unwrap())?; Ok(unpack_dir.to_path_buf()) } @@ -832,9 +878,15 @@ impl<'cfg> Source for RegistrySource<'cfg> { // names to the original name. The resolver will later // reject any candidates that have the wrong name, and with this it'll // along the way produce helpful "did you mean?" suggestions. - for name_permutation in - index::UncanonicalizedIter::new(&dep.package_name()).take(1024) - { + // For now we only try the canonical lysing `-` to `_` and vice versa. + // More advanced fuzzy searching become in the future. + for name_permutation in [ + dep.package_name().replace('-', "_"), + dep.package_name().replace('_', "-"), + ] { + if name_permutation.as_str() == dep.package_name().as_str() { + continue; + } any_pending |= self .index .query_inner( @@ -945,7 +997,7 @@ impl<'cfg> Source for RegistrySource<'cfg> { } /// Get the maximum upack size that Cargo permits -/// based on a given `size of your compressed file. +/// based on a given `size` of your compressed file. /// /// Returns the larger one between `size * max compression ratio` /// and a fixed max unpacked size. @@ -1012,3 +1064,16 @@ mod tests { assert_eq!(make_dep_prefix("aBcDe"), "aB/cD"); } } + +/// Set the current [`umask`] value for the given tarball. No-op on non-Unix +/// platforms. +/// +/// On Windows, tar only looks at user permissions and tries to set the "read +/// only" attribute, so no-op as well. +/// +/// [`umask`]: https://man7.org/linux/man-pages/man2/umask.2.html +#[allow(unused_variables)] +fn set_mask<R: Read>(tar: &mut Archive<R>) { + #[cfg(unix)] + tar.set_mask(crate::util::get_umask()); +} diff --git a/src/tools/cargo/src/cargo/sources/registry/remote.rs b/src/tools/cargo/src/cargo/sources/registry/remote.rs index 3e5029144..f4df4e86b 100644 --- a/src/tools/cargo/src/cargo/sources/registry/remote.rs +++ b/src/tools/cargo/src/cargo/sources/registry/remote.rs @@ -1,5 +1,6 @@ use crate::core::{GitReference, PackageId, SourceId}; use crate::sources::git; +use crate::sources::git::fetch::RemoteKind; use crate::sources::registry::download; use crate::sources::registry::MaybeLock; use crate::sources::registry::{LoadResponse, RegistryConfig, RegistryData}; @@ -304,8 +305,14 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> { // checkout. let url = self.source_id.url(); let repo = self.repo.borrow_mut().unwrap(); - git::fetch(repo, url.as_str(), &self.index_git_ref, self.config) - .with_context(|| format!("failed to fetch `{}`", url))?; + git::fetch( + repo, + url.as_str(), + &self.index_git_ref, + self.config, + RemoteKind::Registry, + ) + .with_context(|| format!("failed to fetch `{}`", url))?; // Create a dummy file to record the mtime for when we updated the // index. diff --git a/src/tools/cargo/src/cargo/sources/replaced.rs b/src/tools/cargo/src/cargo/sources/replaced.rs index 13191d223..eef30e80c 100644 --- a/src/tools/cargo/src/cargo/sources/replaced.rs +++ b/src/tools/cargo/src/cargo/sources/replaced.rs @@ -5,13 +5,24 @@ use std::task::Poll; use anyhow::Context as _; +/// A source that replaces one source with the other. This manages the [source +/// replacement] feature. +/// +/// The implementation is merely redirecting from the original to the replacement. +/// +/// [source replacement]: https://doc.rust-lang.org/nightly/cargo/reference/source-replacement.html pub struct ReplacedSource<'cfg> { + /// The identifier of the original source. to_replace: SourceId, + /// The identifier of the new replacement source. replace_with: SourceId, inner: Box<dyn Source + 'cfg>, } impl<'cfg> ReplacedSource<'cfg> { + /// Creates a replaced source. + /// + /// The `src` argument is the new replacement source. pub fn new( to_replace: SourceId, replace_with: SourceId, diff --git a/src/tools/cargo/src/cargo/util/command_prelude.rs b/src/tools/cargo/src/cargo/util/command_prelude.rs index 2145dbdee..c18785c66 100644 --- a/src/tools/cargo/src/cargo/util/command_prelude.rs +++ b/src/tools/cargo/src/cargo/util/command_prelude.rs @@ -91,10 +91,10 @@ pub trait CommandExt: Sized { all: &'static str, ) -> Self { self.arg_targets_lib_bin_example(lib, bin, bins, example, examples) - ._arg(optional_multi_opt("test", "NAME", test)) ._arg(flag("tests", tests)) - ._arg(optional_multi_opt("bench", "NAME", bench)) + ._arg(optional_multi_opt("test", "NAME", test)) ._arg(flag("benches", benches)) + ._arg(optional_multi_opt("bench", "NAME", bench)) ._arg(flag("all-targets", all)) } @@ -107,10 +107,10 @@ pub trait CommandExt: Sized { examples: &'static str, ) -> Self { self._arg(flag("lib", lib)) - ._arg(optional_multi_opt("bin", "NAME", bin)) ._arg(flag("bins", bins)) - ._arg(optional_multi_opt("example", "NAME", example)) + ._arg(optional_multi_opt("bin", "NAME", bin)) ._arg(flag("examples", examples)) + ._arg(optional_multi_opt("example", "NAME", example)) } fn arg_targets_bins_examples( diff --git a/src/tools/cargo/src/cargo/util/config/mod.rs b/src/tools/cargo/src/cargo/util/config/mod.rs index dad7e9c72..076b78299 100644 --- a/src/tools/cargo/src/cargo/util/config/mod.rs +++ b/src/tools/cargo/src/cargo/util/config/mod.rs @@ -388,7 +388,7 @@ impl Config { /// Gets the path to the `rustdoc` executable. pub fn rustdoc(&self) -> CargoResult<&Path> { self.rustdoc - .try_borrow_with(|| Ok(self.get_tool("rustdoc", &self.build_config()?.rustdoc))) + .try_borrow_with(|| Ok(self.get_tool(Tool::Rustdoc, &self.build_config()?.rustdoc))) .map(AsRef::as_ref) } @@ -406,7 +406,7 @@ impl Config { ); Rustc::new( - self.get_tool("rustc", &self.build_config()?.rustc), + self.get_tool(Tool::Rustc, &self.build_config()?.rustc), wrapper, rustc_workspace_wrapper, &self @@ -1640,11 +1640,63 @@ impl Config { } } - /// Looks for a path for `tool` in an environment variable or config path, defaulting to `tool` - /// as a path. - fn get_tool(&self, tool: &str, from_config: &Option<ConfigRelativePath>) -> PathBuf { - self.maybe_get_tool(tool, from_config) - .unwrap_or_else(|| PathBuf::from(tool)) + /// Returns the path for the given tool. + /// + /// This will look for the tool in the following order: + /// + /// 1. From an environment variable matching the tool name (such as `RUSTC`). + /// 2. From the given config value (which is usually something like `build.rustc`). + /// 3. Finds the tool in the PATH environment variable. + /// + /// This is intended for tools that are rustup proxies. If you need to get + /// a tool that is not a rustup proxy, use `maybe_get_tool` instead. + fn get_tool(&self, tool: Tool, from_config: &Option<ConfigRelativePath>) -> PathBuf { + let tool_str = tool.as_str(); + self.maybe_get_tool(tool_str, from_config) + .or_else(|| { + // This is an optimization to circumvent the rustup proxies + // which can have a significant performance hit. The goal here + // is to determine if calling `rustc` from PATH would end up + // calling the proxies. + // + // This is somewhat cautious trying to determine if it is safe + // to circumvent rustup, because there are some situations + // where users may do things like modify PATH, call cargo + // directly, use a custom rustup toolchain link without a + // cargo executable, etc. However, there is still some risk + // this may make the wrong decision in unusual circumstances. + // + // First, we must be running under rustup in the first place. + let toolchain = self.get_env_os("RUSTUP_TOOLCHAIN")?; + // This currently does not support toolchain paths. + // This also enforces UTF-8. + if toolchain.to_str()?.contains(&['/', '\\']) { + return None; + } + // If the tool on PATH is the same as `rustup` on path, then + // there is pretty good evidence that it will be a proxy. + let tool_resolved = paths::resolve_executable(Path::new(tool_str)).ok()?; + let rustup_resolved = paths::resolve_executable(Path::new("rustup")).ok()?; + let tool_meta = tool_resolved.metadata().ok()?; + let rustup_meta = rustup_resolved.metadata().ok()?; + // This works on the assumption that rustup and its proxies + // use hard links to a single binary. If rustup ever changes + // that setup, then I think the worst consequence is that this + // optimization will not work, and it will take the slow path. + if tool_meta.len() != rustup_meta.len() { + return None; + } + // Try to find the tool in rustup's toolchain directory. + let tool_exe = Path::new(tool_str).with_extension(env::consts::EXE_EXTENSION); + let toolchain_exe = home::rustup_home() + .ok()? + .join("toolchains") + .join(&toolchain) + .join("bin") + .join(&tool_exe); + toolchain_exe.exists().then_some(toolchain_exe) + }) + .unwrap_or_else(|| PathBuf::from(tool_str)) } pub fn jobserver_from_env(&self) -> Option<&jobserver::Client> { @@ -1665,8 +1717,12 @@ impl Config { } pub fn http_config(&self) -> CargoResult<&CargoHttpConfig> { - self.http_config - .try_borrow_with(|| self.get::<CargoHttpConfig>("http")) + self.http_config.try_borrow_with(|| { + let mut http = self.get::<CargoHttpConfig>("http")?; + let curl_v = curl::Version::get(); + disables_multiplexing_for_bad_curl(curl_v.version(), &mut http, self); + Ok(http) + }) } pub fn future_incompat_config(&self) -> CargoResult<&CargoFutureIncompatConfig> { @@ -1693,8 +1749,28 @@ impl Config { .env_config .try_borrow_with(|| self.get::<EnvConfig>("env"))?; - if env_config.get("CARGO_HOME").is_some() { - bail!("setting the `CARGO_HOME` environment variable is not supported in the `[env]` configuration table") + // Reasons for disallowing these values: + // + // - CARGO_HOME: The initial call to cargo does not honor this value + // from the [env] table. Recursive calls to cargo would use the new + // value, possibly behaving differently from the outer cargo. + // + // - RUSTUP_HOME and RUSTUP_TOOLCHAIN: Under normal usage with rustup, + // this will have no effect because the rustup proxy sets + // RUSTUP_HOME and RUSTUP_TOOLCHAIN, and that would override the + // [env] table. If the outer cargo is executed directly + // circumventing the rustup proxy, then this would affect calls to + // rustc (assuming that is a proxy), which could potentially cause + // problems with cargo and rustc being from different toolchains. We + // consider this to be not a use case we would like to support, + // since it will likely cause problems or lead to confusion. + for disallowed in &["CARGO_HOME", "RUSTUP_HOME", "RUSTUP_TOOLCHAIN"] { + if env_config.contains_key(*disallowed) { + bail!( + "setting the `{disallowed}` environment variable is not supported \ + in the `[env]` configuration table" + ); + } } Ok(env_config) @@ -2645,3 +2721,90 @@ macro_rules! drop_eprint { $crate::__shell_print!($config, err, false, $($arg)*) ); } + +enum Tool { + Rustc, + Rustdoc, +} + +impl Tool { + fn as_str(&self) -> &str { + match self { + Tool::Rustc => "rustc", + Tool::Rustdoc => "rustdoc", + } + } +} + +/// Disable HTTP/2 multiplexing for some broken versions of libcurl. +/// +/// In certain versions of libcurl when proxy is in use with HTTP/2 +/// multiplexing, connections will continue stacking up. This was +/// fixed in libcurl 8.0.0 in curl/curl@821f6e2a89de8aec1c7da3c0f381b92b2b801efc +/// +/// However, Cargo can still link against old system libcurl if it is from a +/// custom built one or on macOS. For those cases, multiplexing needs to be +/// disabled when those versions are detected. +fn disables_multiplexing_for_bad_curl( + curl_version: &str, + http: &mut CargoHttpConfig, + config: &Config, +) { + use crate::util::network; + + if network::proxy::http_proxy_exists(http, config) && http.multiplexing.is_none() { + let bad_curl_versions = ["7.87.0", "7.88.0", "7.88.1"]; + if bad_curl_versions + .iter() + .any(|v| curl_version.starts_with(v)) + { + log::info!("disabling multiplexing with proxy, curl version is {curl_version}"); + http.multiplexing = Some(false); + } + } +} + +#[cfg(test)] +mod tests { + use super::disables_multiplexing_for_bad_curl; + use super::CargoHttpConfig; + use super::Config; + use super::Shell; + + #[test] + fn disables_multiplexing() { + let mut config = Config::new(Shell::new(), "".into(), "".into()); + config.set_search_stop_path(std::path::PathBuf::new()); + config.set_env(Default::default()); + + let mut http = CargoHttpConfig::default(); + http.proxy = Some("127.0.0.1:3128".into()); + disables_multiplexing_for_bad_curl("7.88.1", &mut http, &config); + assert_eq!(http.multiplexing, Some(false)); + + let cases = [ + (None, None, "7.87.0", None), + (None, None, "7.88.0", None), + (None, None, "7.88.1", None), + (None, None, "8.0.0", None), + (Some("".into()), None, "7.87.0", Some(false)), + (Some("".into()), None, "7.88.0", Some(false)), + (Some("".into()), None, "7.88.1", Some(false)), + (Some("".into()), None, "8.0.0", None), + (Some("".into()), Some(false), "7.87.0", Some(false)), + (Some("".into()), Some(false), "7.88.0", Some(false)), + (Some("".into()), Some(false), "7.88.1", Some(false)), + (Some("".into()), Some(false), "8.0.0", Some(false)), + ]; + + for (proxy, multiplexing, curl_v, result) in cases { + let mut http = CargoHttpConfig { + multiplexing, + proxy, + ..Default::default() + }; + disables_multiplexing_for_bad_curl(curl_v, &mut http, &config); + assert_eq!(http.multiplexing, result); + } + } +} diff --git a/src/tools/cargo/src/cargo/util/diagnostic_server.rs b/src/tools/cargo/src/cargo/util/diagnostic_server.rs index cc5314260..36215735b 100644 --- a/src/tools/cargo/src/cargo/util/diagnostic_server.rs +++ b/src/tools/cargo/src/cargo/util/diagnostic_server.rs @@ -4,6 +4,7 @@ use std::collections::HashSet; use std::io::{BufReader, Read, Write}; use std::net::{Shutdown, SocketAddr, TcpListener, TcpStream}; +use std::path::PathBuf; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use std::thread::{self, JoinHandle}; @@ -18,16 +19,6 @@ use crate::util::errors::CargoResult; use crate::util::Config; const DIAGNOSTICS_SERVER_VAR: &str = "__CARGO_FIX_DIAGNOSTICS_SERVER"; -const PLEASE_REPORT_THIS_BUG: &str = - "This likely indicates a bug in either rustc or cargo itself,\n\ - and we would appreciate a bug report! You're likely to see \n\ - a number of compiler warnings after this message which cargo\n\ - attempted to fix but failed. If you could open an issue at\n\ - https://github.com/rust-lang/rust/issues\n\ - quoting the full output of this command we'd be very appreciative!\n\ - Note that you may be able to make some more progress in the near-term\n\ - fixing code with the `--broken-code` flag\n\n\ - "; #[derive(Deserialize, Serialize, Hash, Eq, PartialEq, Clone)] pub enum Message { @@ -83,15 +74,27 @@ impl Message { } } +/// A printer that will print diagnostics messages to the shell. pub struct DiagnosticPrinter<'a> { + /// The config to get the shell to print to. config: &'a Config, + /// An optional wrapper to be used in addition to `rustc.wrapper` for workspace crates. + /// This is used to get the correct bug report URL. For instance, + /// if `clippy-driver` is set as the value for the wrapper, + /// then the correct bug report URL for `clippy` can be obtained. + workspace_wrapper: &'a Option<PathBuf>, + // A set of messages that have already been printed. dedupe: HashSet<Message>, } impl<'a> DiagnosticPrinter<'a> { - pub fn new(config: &'a Config) -> DiagnosticPrinter<'a> { + pub fn new( + config: &'a Config, + workspace_wrapper: &'a Option<PathBuf>, + ) -> DiagnosticPrinter<'a> { DiagnosticPrinter { config, + workspace_wrapper, dedupe: HashSet::new(), } } @@ -128,7 +131,12 @@ impl<'a> DiagnosticPrinter<'a> { "The full error message was:\n\n> {}\n\n", message, )?; - write!(self.config.shell().err(), "{}", PLEASE_REPORT_THIS_BUG)?; + let issue_link = get_bug_report_url(self.workspace_wrapper); + write!( + self.config.shell().err(), + "{}", + gen_please_report_this_bug_text(issue_link) + )?; Ok(()) } Message::FixFailed { @@ -159,7 +167,12 @@ impl<'a> DiagnosticPrinter<'a> { } writeln!(self.config.shell().err())?; } - write!(self.config.shell().err(), "{}", PLEASE_REPORT_THIS_BUG)?; + let issue_link = get_bug_report_url(self.workspace_wrapper); + write!( + self.config.shell().err(), + "{}", + gen_please_report_this_bug_text(issue_link) + )?; if !errors.is_empty() { writeln!( self.config.shell().err(), @@ -218,6 +231,31 @@ https://doc.rust-lang.org/edition-guide/editions/transitioning-an-existing-proje } } +fn gen_please_report_this_bug_text(url: &str) -> String { + format!( + "This likely indicates a bug in either rustc or cargo itself,\n\ + and we would appreciate a bug report! You're likely to see \n\ + a number of compiler warnings after this message which cargo\n\ + attempted to fix but failed. If you could open an issue at\n\ + {}\n\ + quoting the full output of this command we'd be very appreciative!\n\ + Note that you may be able to make some more progress in the near-term\n\ + fixing code with the `--broken-code` flag\n\n\ + ", + url + ) +} + +fn get_bug_report_url(rustc_workspace_wrapper: &Option<PathBuf>) -> &str { + let clippy = std::ffi::OsStr::new("clippy-driver"); + let issue_link = match rustc_workspace_wrapper.as_ref().and_then(|x| x.file_stem()) { + Some(wrapper) if wrapper == clippy => "https://github.com/rust-lang/rust-clippy/issues", + _ => "https://github.com/rust-lang/rust/issues", + }; + + issue_link +} + #[derive(Debug)] pub struct RustfixDiagnosticServer { listener: TcpListener, diff --git a/src/tools/cargo/src/cargo/util/edit_distance.rs b/src/tools/cargo/src/cargo/util/edit_distance.rs new file mode 100644 index 000000000..f77e48b44 --- /dev/null +++ b/src/tools/cargo/src/cargo/util/edit_distance.rs @@ -0,0 +1,143 @@ +use std::{cmp, mem}; + +/// Finds the [edit distance] between two strings. +/// +/// Returns `None` if the distance exceeds the limit. +/// +/// [edit distance]: https://en.wikipedia.org/wiki/Edit_distance +pub fn edit_distance(a: &str, b: &str, limit: usize) -> Option<usize> { + // Comparing the strings lowercased will result in a difference in capitalization being less distance away + // than being a completely different letter. Otherwise `CHECK` is as far away from `check` as it + // is from `build` (both with a distance of 5). For a single letter shortcut (e.g. `b` or `c`), they will + // all be as far away from any capital single letter entry (all with a distance of 1). + // By first lowercasing the strings, `C` and `c` are closer than `C` and `b`, for example. + let a = a.to_lowercase(); + let b = b.to_lowercase(); + + let mut a = &a.chars().collect::<Vec<_>>()[..]; + let mut b = &b.chars().collect::<Vec<_>>()[..]; + + // Ensure that `b` is the shorter string, minimizing memory use. + if a.len() < b.len() { + mem::swap(&mut a, &mut b); + } + + let min_dist = a.len() - b.len(); + // If we know the limit will be exceeded, we can return early. + if min_dist > limit { + return None; + } + + // Strip common prefix. + while let Some(((b_char, b_rest), (a_char, a_rest))) = b.split_first().zip(a.split_first()) { + if a_char != b_char { + break; + } + a = a_rest; + b = b_rest; + } + // Strip common suffix. + while let Some(((b_char, b_rest), (a_char, a_rest))) = b.split_last().zip(a.split_last()) { + if a_char != b_char { + break; + } + a = a_rest; + b = b_rest; + } + + // If either string is empty, the distance is the length of the other. + // We know that `b` is the shorter string, so we don't need to check `a`. + if b.len() == 0 { + return Some(min_dist); + } + + let mut prev_prev = vec![usize::MAX; b.len() + 1]; + let mut prev = (0..=b.len()).collect::<Vec<_>>(); + let mut current = vec![0; b.len() + 1]; + + // row by row + for i in 1..=a.len() { + current[0] = i; + let a_idx = i - 1; + + // column by column + for j in 1..=b.len() { + let b_idx = j - 1; + + // There is no cost to substitute a character with itself. + let substitution_cost = if a[a_idx] == b[b_idx] { 0 } else { 1 }; + + current[j] = cmp::min( + // deletion + prev[j] + 1, + cmp::min( + // insertion + current[j - 1] + 1, + // substitution + prev[j - 1] + substitution_cost, + ), + ); + + if (i > 1) && (j > 1) && (a[a_idx] == b[b_idx - 1]) && (a[a_idx - 1] == b[b_idx]) { + // transposition + current[j] = cmp::min(current[j], prev_prev[j - 2] + 1); + } + } + + // Rotate the buffers, reusing the memory. + [prev_prev, prev, current] = [prev, current, prev_prev]; + } + + // `prev` because we already rotated the buffers. + let distance = prev[b.len()]; + (distance <= limit).then_some(distance) +} + +/// Find the closest element from `iter` matching `choice`. The `key` callback +/// is used to select a `&str` from the iterator to compare against `choice`. +pub fn closest<'a, T>( + choice: &str, + iter: impl Iterator<Item = T>, + key: impl Fn(&T) -> &'a str, +) -> Option<T> { + // Only consider candidates with an edit distance of 3 or less so we don't + // suggest out-of-the-blue options. + iter.filter_map(|e| Some((edit_distance(choice, key(&e), 3)?, e))) + .min_by_key(|t| t.0) + .map(|t| t.1) +} + +/// Version of `closest` that returns a common "suggestion" that can be tacked +/// onto the end of an error message. +pub fn closest_msg<'a, T>( + choice: &str, + iter: impl Iterator<Item = T>, + key: impl Fn(&T) -> &'a str, +) -> String { + match closest(choice, iter, &key) { + Some(e) => format!("\n\n\tDid you mean `{}`?", key(&e)), + None => String::new(), + } +} + +#[test] +fn test_edit_distance() { + use std::char::{from_u32, MAX}; + // Test bytelength agnosticity + for c in (0u32..MAX as u32) + .filter_map(from_u32) + .map(|i| i.to_string()) + { + assert_eq!(edit_distance(&c, &c, usize::MAX), Some(0)); + } + + let a = "\nMäry häd ä little lämb\n\nLittle lämb\n"; + let b = "\nMary häd ä little lämb\n\nLittle lämb\n"; + let c = "Mary häd ä little lämb\n\nLittle lämb\n"; + assert_eq!(edit_distance(a, b, usize::MAX), Some(1)); + assert_eq!(edit_distance(b, a, usize::MAX), Some(1)); + assert_eq!(edit_distance(a, c, usize::MAX), Some(2)); + assert_eq!(edit_distance(c, a, usize::MAX), Some(2)); + assert_eq!(edit_distance(b, c, usize::MAX), Some(1)); + assert_eq!(edit_distance(c, b, usize::MAX), Some(1)); +} diff --git a/src/tools/cargo/src/cargo/util/lev_distance.rs b/src/tools/cargo/src/cargo/util/lev_distance.rs deleted file mode 100644 index 8dcef4a89..000000000 --- a/src/tools/cargo/src/cargo/util/lev_distance.rs +++ /dev/null @@ -1,93 +0,0 @@ -use std::cmp; - -pub fn lev_distance(me: &str, t: &str) -> usize { - // Comparing the strings lowercased will result in a difference in capitalization being less distance away - // than being a completely different letter. Otherwise `CHECK` is as far away from `check` as it - // is from `build` (both with a distance of 5). For a single letter shortcut (e.g. `b` or `c`), they will - // all be as far away from any capital single letter entry (all with a distance of 1). - // By first lowercasing the strings, `C` and `c` are closer than `C` and `b`, for example. - let me = me.to_lowercase(); - let t = t.to_lowercase(); - - let t_len = t.chars().count(); - if me.is_empty() { - return t_len; - } - if t.is_empty() { - return me.chars().count(); - } - - let mut dcol = (0..=t_len).collect::<Vec<_>>(); - let mut t_last = 0; - - for (i, sc) in me.chars().enumerate() { - let mut current = i; - dcol[0] = current + 1; - - for (j, tc) in t.chars().enumerate() { - let next = dcol[j + 1]; - - if sc == tc { - dcol[j + 1] = current; - } else { - dcol[j + 1] = cmp::min(current, next); - dcol[j + 1] = cmp::min(dcol[j + 1], dcol[j]) + 1; - } - - current = next; - t_last = j; - } - } - - dcol[t_last + 1] -} - -/// Find the closest element from `iter` matching `choice`. The `key` callback -/// is used to select a `&str` from the iterator to compare against `choice`. -pub fn closest<'a, T>( - choice: &str, - iter: impl Iterator<Item = T>, - key: impl Fn(&T) -> &'a str, -) -> Option<T> { - // Only consider candidates with a lev_distance of 3 or less so we don't - // suggest out-of-the-blue options. - iter.map(|e| (lev_distance(choice, key(&e)), e)) - .filter(|&(d, _)| d < 4) - .min_by_key(|t| t.0) - .map(|t| t.1) -} - -/// Version of `closest` that returns a common "suggestion" that can be tacked -/// onto the end of an error message. -pub fn closest_msg<'a, T>( - choice: &str, - iter: impl Iterator<Item = T>, - key: impl Fn(&T) -> &'a str, -) -> String { - match closest(choice, iter, &key) { - Some(e) => format!("\n\n\tDid you mean `{}`?", key(&e)), - None => String::new(), - } -} - -#[test] -fn test_lev_distance() { - use std::char::{from_u32, MAX}; - // Test bytelength agnosticity - for c in (0u32..MAX as u32) - .filter_map(from_u32) - .map(|i| i.to_string()) - { - assert_eq!(lev_distance(&c, &c), 0); - } - - let a = "\nMäry häd ä little lämb\n\nLittle lämb\n"; - let b = "\nMary häd ä little lämb\n\nLittle lämb\n"; - let c = "Mary häd ä little lämb\n\nLittle lämb\n"; - assert_eq!(lev_distance(a, b), 1); - assert_eq!(lev_distance(b, a), 1); - assert_eq!(lev_distance(a, c), 2); - assert_eq!(lev_distance(c, a), 2); - assert_eq!(lev_distance(b, c), 1); - assert_eq!(lev_distance(c, b), 1); -} diff --git a/src/tools/cargo/src/cargo/util/machine_message.rs b/src/tools/cargo/src/cargo/util/machine_message.rs index baef5167b..f1602ae57 100644 --- a/src/tools/cargo/src/cargo/util/machine_message.rs +++ b/src/tools/cargo/src/cargo/util/machine_message.rs @@ -55,12 +55,20 @@ impl<'a> Message for Artifact<'a> { #[derive(Serialize)] pub struct ArtifactProfile { pub opt_level: &'static str, - pub debuginfo: Option<u32>, + pub debuginfo: Option<ArtifactDebuginfo>, pub debug_assertions: bool, pub overflow_checks: bool, pub test: bool, } +/// Internally this is an enum with different variants, but keep using 0/1/2 as integers for compatibility. +#[derive(Serialize)] +#[serde(untagged)] +pub enum ArtifactDebuginfo { + Int(u32), + Named(&'static str), +} + #[derive(Serialize)] pub struct BuildScript<'a> { pub package_id: PackageId, diff --git a/src/tools/cargo/src/cargo/util/mod.rs b/src/tools/cargo/src/cargo/util/mod.rs index 12b152018..df8dcb0ac 100644 --- a/src/tools/cargo/src/cargo/util/mod.rs +++ b/src/tools/cargo/src/cargo/util/mod.rs @@ -7,6 +7,7 @@ pub use self::config::{homedir, Config, ConfigValue}; pub(crate) use self::counter::MetricsCounter; pub use self::dependency_queue::DependencyQueue; pub use self::diagnostic_server::RustfixDiagnosticServer; +pub use self::edit_distance::{closest, closest_msg, edit_distance}; pub use self::errors::CliError; pub use self::errors::{internal, CargoResult, CliResult}; pub use self::flock::{FileLock, Filesystem}; @@ -16,7 +17,6 @@ pub use self::hex::{hash_u64, short_hash, to_hex}; pub use self::into_url::IntoUrl; pub use self::into_url_with_base::IntoUrlWithBase; pub(crate) use self::io::LimitErrorReader; -pub use self::lev_distance::{closest, closest_msg, lev_distance}; pub use self::lockserver::{LockServer, LockServerClient, LockServerStarted}; pub use self::progress::{Progress, ProgressStyle}; pub use self::queue::Queue; @@ -38,6 +38,7 @@ mod counter; pub mod cpu; mod dependency_queue; pub mod diagnostic_server; +pub mod edit_distance; pub mod errors; mod flock; pub mod graph; @@ -49,7 +50,6 @@ pub mod into_url; mod into_url_with_base; mod io; pub mod job; -pub mod lev_distance; mod lockserver; pub mod machine_message; pub mod network; @@ -207,6 +207,24 @@ pub fn try_canonicalize<P: AsRef<Path>>(path: P) -> std::io::Result<PathBuf> { }) } +/// Get the current [`umask`] value. +/// +/// [`umask`]: https://man7.org/linux/man-pages/man2/umask.2.html +#[cfg(unix)] +pub fn get_umask() -> u32 { + use std::sync::OnceLock; + static UMASK: OnceLock<libc::mode_t> = OnceLock::new(); + // SAFETY: Syscalls are unsafe. Calling `umask` twice is even unsafer for + // multithreading program, since it doesn't provide a way to retrive the + // value without modifications. We use a static `OnceLock` here to ensure + // it only gets call once during the entire program lifetime. + *UMASK.get_or_init(|| unsafe { + let umask = libc::umask(0o022); + libc::umask(umask); + umask + }) as u32 // it is u16 on macos +} + #[cfg(test)] mod test { use super::*; diff --git a/src/tools/cargo/src/cargo/util/network/mod.rs b/src/tools/cargo/src/cargo/util/network/mod.rs index 60a380343..2006bb65f 100644 --- a/src/tools/cargo/src/cargo/util/network/mod.rs +++ b/src/tools/cargo/src/cargo/util/network/mod.rs @@ -2,6 +2,7 @@ use std::task::Poll; +pub mod proxy; pub mod retry; pub mod sleep; diff --git a/src/tools/cargo/src/cargo/util/network/proxy.rs b/src/tools/cargo/src/cargo/util/network/proxy.rs new file mode 100644 index 000000000..e305cf1ff --- /dev/null +++ b/src/tools/cargo/src/cargo/util/network/proxy.rs @@ -0,0 +1,42 @@ +//! Utilities for network proxies. + +use crate::util::config::CargoHttpConfig; +use crate::util::config::Config; + +/// Proxy environment variables that are picked up by libcurl. +const LIBCURL_HTTP_PROXY_ENVS: [&str; 4] = + ["http_proxy", "HTTP_PROXY", "https_proxy", "HTTPS_PROXY"]; + +/// Finds an explicit HTTP proxy if one is available. +/// +/// Favor [Cargo's `http.proxy`], then [Git's `http.proxy`]. +/// Proxies specified via environment variables are picked up by libcurl. +/// See [`LIBCURL_HTTP_PROXY_ENVS`]. +/// +/// [Cargo's `http.proxy`]: https://doc.rust-lang.org/nightly/cargo/reference/config.html#httpproxy +/// [Git's `http.proxy`]: https://git-scm.com/docs/git-config#Documentation/git-config.txt-httpproxy +pub fn http_proxy(http: &CargoHttpConfig) -> Option<String> { + if let Some(s) = &http.proxy { + return Some(s.into()); + } + git2::Config::open_default() + .and_then(|cfg| cfg.get_string("http.proxy")) + .ok() +} + +/// Determine if an http proxy exists. +/// +/// Checks the following for existence, in order: +/// +/// * Cargo's `http.proxy` +/// * Git's `http.proxy` +/// * `http_proxy` env var +/// * `HTTP_PROXY` env var +/// * `https_proxy` env var +/// * `HTTPS_PROXY` env var +pub fn http_proxy_exists(http: &CargoHttpConfig, config: &Config) -> bool { + http_proxy(http).is_some() + || LIBCURL_HTTP_PROXY_ENVS + .iter() + .any(|v| config.get_env(v).is_ok()) +} diff --git a/src/tools/cargo/src/cargo/util/toml/mod.rs b/src/tools/cargo/src/cargo/util/toml/mod.rs index 9e7c6f63e..2c213b7f5 100644 --- a/src/tools/cargo/src/cargo/util/toml/mod.rs +++ b/src/tools/cargo/src/cargo/util/toml/mod.rs @@ -1,5 +1,5 @@ use std::collections::{BTreeMap, BTreeSet, HashMap}; -use std::fmt; +use std::fmt::{self, Display, Write}; use std::marker::PhantomData; use std::path::{Path, PathBuf}; use std::rc::Rc; @@ -12,8 +12,8 @@ use itertools::Itertools; use lazycell::LazyCell; use log::{debug, trace}; use semver::{self, VersionReq}; -use serde::de; use serde::de::IntoDeserializer as _; +use serde::de::{self, Unexpected}; use serde::ser; use serde::{Deserialize, Serialize}; use url::Url; @@ -355,6 +355,7 @@ pub struct TomlManifest { patch: Option<BTreeMap<String, BTreeMap<String, TomlDependency>>>, workspace: Option<TomlWorkspace>, badges: Option<MaybeWorkspaceBtreeMap>, + lints: Option<toml::Value>, } #[derive(Deserialize, Serialize, Clone, Debug, Default)] @@ -442,11 +443,100 @@ impl ser::Serialize for TomlOptLevel { } } -#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] -#[serde(untagged, expecting = "expected a boolean or an integer")] -pub enum U32OrBool { - U32(u32), - Bool(bool), +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)] +pub enum TomlDebugInfo { + None, + LineDirectivesOnly, + LineTablesOnly, + Limited, + Full, +} + +impl ser::Serialize for TomlDebugInfo { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: ser::Serializer, + { + match self { + Self::None => 0.serialize(serializer), + Self::LineDirectivesOnly => "line-directives-only".serialize(serializer), + Self::LineTablesOnly => "line-tables-only".serialize(serializer), + Self::Limited => 1.serialize(serializer), + Self::Full => 2.serialize(serializer), + } + } +} + +impl<'de> de::Deserialize<'de> for TomlDebugInfo { + fn deserialize<D>(d: D) -> Result<TomlDebugInfo, D::Error> + where + D: de::Deserializer<'de>, + { + struct Visitor; + + impl<'de> de::Visitor<'de> for Visitor { + type Value = TomlDebugInfo; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str( + "a boolean, 0, 1, 2, \"line-tables-only\", or \"line-directives-only\"", + ) + } + + fn visit_i64<E>(self, value: i64) -> Result<TomlDebugInfo, E> + where + E: de::Error, + { + let debuginfo = match value { + 0 => TomlDebugInfo::None, + 1 => TomlDebugInfo::Limited, + 2 => TomlDebugInfo::Full, + _ => return Err(de::Error::invalid_value(Unexpected::Signed(value), &self)), + }; + Ok(debuginfo) + } + + fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E> + where + E: de::Error, + { + Ok(if v { + TomlDebugInfo::Full + } else { + TomlDebugInfo::None + }) + } + + fn visit_str<E>(self, value: &str) -> Result<TomlDebugInfo, E> + where + E: de::Error, + { + let debuginfo = match value { + "none" => TomlDebugInfo::None, + "limited" => TomlDebugInfo::Limited, + "full" => TomlDebugInfo::Full, + "line-directives-only" => TomlDebugInfo::LineDirectivesOnly, + "line-tables-only" => TomlDebugInfo::LineTablesOnly, + _ => return Err(de::Error::invalid_value(Unexpected::Str(value), &self)), + }; + Ok(debuginfo) + } + } + + d.deserialize_any(Visitor) + } +} + +impl Display for TomlDebugInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + TomlDebugInfo::None => f.write_char('0'), + TomlDebugInfo::Limited => f.write_char('1'), + TomlDebugInfo::Full => f.write_char('2'), + TomlDebugInfo::LineDirectivesOnly => f.write_str("line-directives-only"), + TomlDebugInfo::LineTablesOnly => f.write_str("line-tables-only"), + } + } } #[derive(Deserialize, Serialize, Clone, Debug, Default, Eq, PartialEq)] @@ -456,7 +546,7 @@ pub struct TomlProfile { pub lto: Option<StringOrBool>, pub codegen_backend: Option<InternedString>, pub codegen_units: Option<u32>, - pub debug: Option<U32OrBool>, + pub debug: Option<TomlDebugInfo>, pub split_debuginfo: Option<String>, pub debug_assertions: Option<bool>, pub rpath: Option<bool>, @@ -1332,6 +1422,29 @@ impl<'de> de::Deserialize<'de> for MaybeWorkspaceBtreeMap { } } +type MaybeWorkspaceLints = MaybeWorkspace<TomlLints, TomlWorkspaceField>; + +impl<'de> de::Deserialize<'de> for MaybeWorkspaceLints { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: de::Deserializer<'de>, + { + let value = serde_value::Value::deserialize(deserializer)?; + + if let Ok(w) = TomlWorkspaceField::deserialize( + serde_value::ValueDeserializer::<D::Error>::new(value.clone()), + ) { + return if w.workspace() { + Ok(MaybeWorkspace::Workspace(w)) + } else { + Err(de::Error::custom("`workspace` cannot be false")) + }; + } + TomlLints::deserialize(serde_value::ValueDeserializer::<D::Error>::new(value)) + .map(MaybeWorkspace::Defined) + } +} + #[derive(Deserialize, Serialize, Clone, Debug)] pub struct TomlWorkspaceField { #[serde(deserialize_with = "bool_no_false")] @@ -1418,6 +1531,7 @@ pub struct TomlWorkspace { // Properties that can be inherited by members. package: Option<InheritableFields>, dependencies: Option<BTreeMap<String, TomlDependency>>, + lints: Option<toml::Value>, // Note that this field must come last due to the way toml serialization // works which requires tables to be emitted after all values. @@ -1431,6 +1545,9 @@ pub struct InheritableFields { // and we don't want it present when serializing #[serde(skip)] dependencies: Option<BTreeMap<String, TomlDependency>>, + #[serde(skip)] + lints: Option<TomlLints>, + version: Option<semver::Version>, authors: Option<Vec<String>>, description: Option<String>, @@ -1461,6 +1578,10 @@ impl InheritableFields { self.dependencies = deps; } + pub fn update_lints(&mut self, lints: Option<TomlLints>) { + self.lints = lints; + } + pub fn update_ws_path(&mut self, ws_root: PathBuf) { self.ws_root = ws_root; } @@ -1472,6 +1593,12 @@ impl InheritableFields { ) } + pub fn lints(&self) -> CargoResult<TomlLints> { + self.lints + .clone() + .map_or(Err(anyhow!("`workspace.lints` was not defined")), |d| Ok(d)) + } + pub fn get_dependency(&self, name: &str, package_root: &Path) -> CargoResult<TomlDependency> { self.dependencies.clone().map_or( Err(anyhow!("`workspace.dependencies` was not defined")), @@ -1789,6 +1916,7 @@ impl TomlManifest { workspace: None, badges: self.badges.clone(), cargo_features: self.cargo_features.clone(), + lints: self.lints.clone(), }); fn map_deps( @@ -1917,6 +2045,9 @@ impl TomlManifest { let mut inheritable = toml_config.package.clone().unwrap_or_default(); inheritable.update_ws_path(package_root.to_path_buf()); inheritable.update_deps(toml_config.dependencies.clone()); + let lints = parse_unstable_lints(toml_config.lints.clone(), config, &mut warnings)?; + let lints = verify_lints(lints)?; + inheritable.update_lints(lints); if let Some(ws_deps) = &inheritable.dependencies { for (name, dep) in ws_deps { unused_dep_keys( @@ -2180,6 +2311,14 @@ impl TomlManifest { &inherit_cell, )?; + let lints = + parse_unstable_lints::<MaybeWorkspaceLints>(me.lints.clone(), config, cx.warnings)? + .map(|mw| mw.resolve("lints", || inherit()?.lints())) + .transpose()?; + let lints = verify_lints(lints)?; + let default = TomlLints::default(); + let rustflags = lints_to_rustflags(lints.as_ref().unwrap_or(&default)); + let mut target: BTreeMap<String, TomlPlatform> = BTreeMap::new(); for (name, platform) in me.target.iter().flatten() { cx.platform = { @@ -2278,6 +2417,7 @@ impl TomlManifest { deps, me.features.as_ref().unwrap_or(&empty_features), package.links.as_deref(), + rust_version.as_deref().map(InternedString::new), )?; let metadata = ManifestMetadata { @@ -2344,6 +2484,11 @@ impl TomlManifest { .transpose()? .unwrap_or_default(), links: package.links.clone(), + rust_version: package + .rust_version + .clone() + .map(|mw| mw.resolve("rust-version", || inherit()?.rust_version())) + .transpose()?, }; package.description = metadata .description @@ -2471,6 +2616,8 @@ impl TomlManifest { .badges .as_ref() .map(|_| MaybeWorkspace::Defined(metadata.badges.clone())), + lints: lints + .map(|lints| toml::Value::try_from(MaybeWorkspaceLints::Defined(lints)).unwrap()), }; let mut manifest = Manifest::new( summary, @@ -2495,6 +2642,7 @@ impl TomlManifest { Rc::new(resolved_toml), package.metabuild.clone().map(|sov| sov.0), resolve_behavior, + rustflags, ); if package.license_file.is_some() && package.license.is_some() { manifest.warnings_mut().add_warning( @@ -2600,6 +2748,9 @@ impl TomlManifest { let mut inheritable = toml_config.package.clone().unwrap_or_default(); inheritable.update_ws_path(root.to_path_buf()); inheritable.update_deps(toml_config.dependencies.clone()); + let lints = parse_unstable_lints(toml_config.lints.clone(), config, &mut warnings)?; + let lints = verify_lints(lints)?; + inheritable.update_lints(lints); let ws_root_config = WorkspaceRootConfig::new( root, &toml_config.members, @@ -2744,6 +2895,107 @@ impl TomlManifest { } } +fn parse_unstable_lints<T: Deserialize<'static>>( + lints: Option<toml::Value>, + config: &Config, + warnings: &mut Vec<String>, +) -> CargoResult<Option<T>> { + let Some(lints) = lints else { return Ok(None); }; + + if !config.cli_unstable().lints { + warn_for_lint_feature(config, warnings); + return Ok(None); + } + + lints.try_into().map(Some).map_err(|err| err.into()) +} + +fn warn_for_lint_feature(config: &Config, warnings: &mut Vec<String>) { + use std::fmt::Write as _; + + let key_name = "lints"; + let feature_name = "lints"; + + let mut message = String::new(); + + let _ = write!( + message, + "unused manifest key `{key_name}` (may be supported in a future version)" + ); + if config.nightly_features_allowed { + let _ = write!( + message, + " + +consider passing `-Z{feature_name}` to enable this feature." + ); + } else { + let _ = write!( + message, + " + +this Cargo does not support nightly features, but if you +switch to nightly channel you can pass +`-Z{feature_name}` to enable this feature.", + ); + } + warnings.push(message); +} + +fn verify_lints(lints: Option<TomlLints>) -> CargoResult<Option<TomlLints>> { + let Some(lints) = lints else { return Ok(None); }; + + for (tool, lints) in &lints { + let supported = ["rust", "clippy", "rustdoc"]; + if !supported.contains(&tool.as_str()) { + let supported = supported.join(", "); + anyhow::bail!("unsupported `{tool}` in `[lints]`, must be one of {supported}") + } + for name in lints.keys() { + if let Some((prefix, suffix)) = name.split_once("::") { + if tool == prefix { + anyhow::bail!( + "`lints.{tool}.{name}` is not valid lint name; try `lints.{prefix}.{suffix}`" + ) + } else if tool == "rust" && supported.contains(&prefix) { + anyhow::bail!( + "`lints.{tool}.{name}` is not valid lint name; try `lints.{prefix}.{suffix}`" + ) + } else { + anyhow::bail!("`lints.{tool}.{name}` is not a valid lint name") + } + } + } + } + + Ok(Some(lints)) +} + +fn lints_to_rustflags(lints: &TomlLints) -> Vec<String> { + let mut rustflags = lints + .iter() + .flat_map(|(tool, lints)| { + lints.iter().map(move |(name, config)| { + let flag = config.level().flag(); + let option = if tool == "rust" { + format!("{flag}={name}") + } else { + format!("{flag}={tool}::{name}") + }; + ( + config.priority(), + // Since the most common group will be `all`, put it last so people are more + // likely to notice that they need to use `priority`. + std::cmp::Reverse(name), + option, + ) + }) + }) + .collect::<Vec<_>>(); + rustflags.sort(); + rustflags.into_iter().map(|(_, _, option)| option).collect() +} + fn unused_dep_keys( dep_name: &str, kind: &str, @@ -2908,8 +3160,8 @@ impl<P: ResolveToPath + Clone> DetailedTomlDependency<P> { if self.version.is_none() && self.path.is_none() && self.git.is_none() { let msg = format!( "dependency ({}) specified without \ - providing a local path, Git repository, or \ - version to use. This will be considered an \ + providing a local path, Git repository, version, or \ + workspace dependency to use. This will be considered an \ error in future versions", name_in_toml ); @@ -3301,3 +3553,58 @@ impl fmt::Debug for PathValue { self.0.fmt(f) } } + +pub type TomlLints = BTreeMap<String, TomlToolLints>; + +pub type TomlToolLints = BTreeMap<String, TomlLint>; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(untagged)] +pub enum TomlLint { + Level(TomlLintLevel), + Config(TomlLintConfig), +} + +impl TomlLint { + fn level(&self) -> TomlLintLevel { + match self { + Self::Level(level) => *level, + Self::Config(config) => config.level, + } + } + + fn priority(&self) -> i8 { + match self { + Self::Level(_) => 0, + Self::Config(config) => config.priority, + } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "kebab-case")] +pub struct TomlLintConfig { + level: TomlLintLevel, + #[serde(default)] + priority: i8, +} + +#[derive(Serialize, Deserialize, Debug, Copy, Clone)] +#[serde(rename_all = "kebab-case")] +pub enum TomlLintLevel { + Forbid, + Deny, + Warn, + Allow, +} + +impl TomlLintLevel { + fn flag(&self) -> &'static str { + match self { + Self::Forbid => "--forbid", + Self::Deny => "--deny", + Self::Warn => "--warn", + Self::Allow => "--allow", + } + } +} diff --git a/src/tools/cargo/src/cargo/util/toml_mut/dependency.rs b/src/tools/cargo/src/cargo/util/toml_mut/dependency.rs index d8a2f2750..1b24833c1 100644 --- a/src/tools/cargo/src/cargo/util/toml_mut/dependency.rs +++ b/src/tools/cargo/src/cargo/util/toml_mut/dependency.rs @@ -225,62 +225,72 @@ impl Dependency { (key.to_owned(), None) }; - let source: Source = - if let Some(git) = table.get("git") { - let mut src = GitSource::new( - git.as_str() - .ok_or_else(|| invalid_type(key, "git", git.type_name(), "string"))?, - ); - if let Some(value) = table.get("branch") { - src = src.set_branch(value.as_str().ok_or_else(|| { + let source: Source = if let Some(git) = table.get("git") { + let mut src = GitSource::new( + git.as_str() + .ok_or_else(|| invalid_type(key, "git", git.type_name(), "string"))?, + ); + if let Some(value) = table.get("branch") { + src = + src.set_branch(value.as_str().ok_or_else(|| { invalid_type(key, "branch", value.type_name(), "string") })?); - } - if let Some(value) = table.get("tag") { - src = src.set_tag(value.as_str().ok_or_else(|| { + } + if let Some(value) = table.get("tag") { + src = + src.set_tag(value.as_str().ok_or_else(|| { invalid_type(key, "tag", value.type_name(), "string") })?); - } - if let Some(value) = table.get("rev") { - src = src.set_rev(value.as_str().ok_or_else(|| { + } + if let Some(value) = table.get("rev") { + src = + src.set_rev(value.as_str().ok_or_else(|| { invalid_type(key, "rev", value.type_name(), "string") })?); - } - if let Some(value) = table.get("version") { - src = src.set_version(value.as_str().ok_or_else(|| { - invalid_type(key, "version", value.type_name(), "string") - })?); - } - src.into() - } else if let Some(path) = table.get("path") { - let path = crate_root + } + if let Some(value) = table.get("version") { + src = src.set_version(value.as_str().ok_or_else(|| { + invalid_type(key, "version", value.type_name(), "string") + })?); + } + src.into() + } else if let Some(path) = table.get("path") { + let path = + crate_root .join(path.as_str().ok_or_else(|| { invalid_type(key, "path", path.type_name(), "string") })?); - let mut src = PathSource::new(path); - if let Some(value) = table.get("version") { - src = src.set_version(value.as_str().ok_or_else(|| { - invalid_type(key, "version", value.type_name(), "string") - })?); - } - src.into() - } else if let Some(version) = table.get("version") { - let src = RegistrySource::new(version.as_str().ok_or_else(|| { + let mut src = PathSource::new(path); + if let Some(value) = table.get("version") { + src = src.set_version(value.as_str().ok_or_else(|| { + invalid_type(key, "version", value.type_name(), "string") + })?); + } + src.into() + } else if let Some(version) = table.get("version") { + let src = + RegistrySource::new(version.as_str().ok_or_else(|| { invalid_type(key, "version", version.type_name(), "string") })?); - src.into() - } else if let Some(workspace) = table.get("workspace") { - let workspace_bool = workspace.as_bool().ok_or_else(|| { - invalid_type(key, "workspace", workspace.type_name(), "bool") - })?; - if !workspace_bool { - anyhow::bail!("`{key}.workspace = false` is unsupported") - } - let src = WorkspaceSource::new(); - src.into() - } else { - anyhow::bail!("Unrecognized dependency source for `{key}`"); - }; + src.into() + } else if let Some(workspace) = table.get("workspace") { + let workspace_bool = workspace + .as_bool() + .ok_or_else(|| invalid_type(key, "workspace", workspace.type_name(), "bool"))?; + if !workspace_bool { + anyhow::bail!("`{key}.workspace = false` is unsupported") + } + let src = WorkspaceSource::new(); + src.into() + } else { + let mut msg = format!("unrecognized dependency source for `{key}`"); + if table.is_empty() { + msg.push_str( + ", expected a local path, Git repository, version, or workspace dependency to be specified", + ); + } + anyhow::bail!(msg); + }; let registry = if let Some(value) = table.get("registry") { Some( value diff --git a/src/tools/cargo/src/doc/README.md b/src/tools/cargo/src/doc/README.md index 79181b7f6..d67838868 100644 --- a/src/tools/cargo/src/doc/README.md +++ b/src/tools/cargo/src/doc/README.md @@ -50,17 +50,17 @@ directory) to three different formats: 3. Plain text (needed for embedded man pages on platforms without man such as Windows), saved in [`src/doc/man/generated_txt/`](man/generated_txt). -To rebuild the man pages, run the script `build-man.sh` in the `src/doc` directory. - -```console -$ ./build-man.sh -``` +To rebuild the man pages, run `cargo build-man` inside the workspace. ### SemVer chapter tests There is a script to verify that the examples in the SemVer chapter work as -intended. To run the tests, go into the `semver-check` directory and run -`cargo run`. +intended. To run the tests, run `cargo +stable run -p semver-check`. + +Note that these tests run on the most recent stable release because they +validate the output of the compiler diagnostics. The output can change between +releases, so we pin to a specific release to avoid frequent and unexpected +breakage. ## Contributing diff --git a/src/tools/cargo/src/doc/build-man.sh b/src/tools/cargo/src/doc/build-man.sh deleted file mode 100755 index 7b1330b58..000000000 --- a/src/tools/cargo/src/doc/build-man.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -# -# This script builds the Cargo man pages. -# -# The source for the man pages are located in src/doc/man/ in markdown format. -# These also are handlebars templates, see crates/mdman/README.md for details. -# -# The generated man pages are placed in the src/etc/man/ directory. The pages -# are also expanded into markdown (after being expanded by handlebars) and -# saved in the src/doc/src/commands/ directory. These are included in the -# Cargo book, which is converted to HTML by mdbook. - -set -e - -cd "$(dirname "${BASH_SOURCE[0]}")" - -OPTIONS="--url https://doc.rust-lang.org/cargo/commands/ \ - --man rustc:1=https://doc.rust-lang.org/rustc/index.html \ - --man rustdoc:1=https://doc.rust-lang.org/rustdoc/index.html" - -cargo run --manifest-path=../../crates/mdman/Cargo.toml -- \ - -t md -o src/commands man/cargo*.md \ - $OPTIONS - -cargo run --manifest-path=../../crates/mdman/Cargo.toml -- \ - -t txt -o man/generated_txt man/cargo*.md \ - $OPTIONS - -cargo run --manifest-path=../../crates/mdman/Cargo.toml -- \ - -t man -o ../etc/man man/cargo*.md \ - $OPTIONS diff --git a/src/tools/cargo/src/doc/contrib/src/SUMMARY.md b/src/tools/cargo/src/doc/contrib/src/SUMMARY.md index 643cc5ac7..053a9db35 100644 --- a/src/tools/cargo/src/doc/contrib/src/SUMMARY.md +++ b/src/tools/cargo/src/doc/contrib/src/SUMMARY.md @@ -2,6 +2,7 @@ - [Introduction](./index.md) - [Issue Tracker](./issues.md) +- [Cargo Team](./team.md) - [Process](./process/index.md) - [Working on Cargo](./process/working-on-cargo.md) - [Release process](./process/release.md) diff --git a/src/tools/cargo/src/doc/contrib/src/implementation/console.md b/src/tools/cargo/src/doc/contrib/src/implementation/console.md index a73d232e0..99d31b951 100644 --- a/src/tools/cargo/src/doc/contrib/src/implementation/console.md +++ b/src/tools/cargo/src/doc/contrib/src/implementation/console.md @@ -19,7 +19,7 @@ the [`JobQueue`] as it processes each message. [`Shell`]: https://github.com/rust-lang/cargo/blob/master/src/cargo/core/shell.rs [`Config`]: https://github.com/rust-lang/cargo/blob/master/src/cargo/util/config/mod.rs [`drop_print`]: https://github.com/rust-lang/cargo/blob/e4b65bdc80f2a293447f2f6a808fa7c84bf9a357/src/cargo/util/config/mod.rs#L1820-L1848 -[`JobQueue`]: https://github.com/rust-lang/cargo/blob/master/src/cargo/core/compiler/job_queue.rs +[`JobQueue`]: https://github.com/rust-lang/cargo/blob/master/src/cargo/core/compiler/job_queue/mod.rs ## Errors diff --git a/src/tools/cargo/src/doc/contrib/src/implementation/filesystem.md b/src/tools/cargo/src/doc/contrib/src/implementation/filesystem.md index 0f70c5833..3c1b2dbd5 100644 --- a/src/tools/cargo/src/doc/contrib/src/implementation/filesystem.md +++ b/src/tools/cargo/src/doc/contrib/src/implementation/filesystem.md @@ -17,5 +17,5 @@ its best to handle them. Some examples of issues to deal with: fractional part of the time stamp. * Symlinks are not always supported, particularly on Windows. -[`fingerprint`]: https://github.com/rust-lang/cargo/blob/master/src/cargo/core/compiler/fingerprint.rs +[`fingerprint`]: https://github.com/rust-lang/cargo/blob/master/src/cargo/core/compiler/fingerprint/mod.rs [`fs::canonicalize`]: https://doc.rust-lang.org/std/fs/fn.canonicalize.html diff --git a/src/tools/cargo/src/doc/contrib/src/index.md b/src/tools/cargo/src/doc/contrib/src/index.md index 5ab169ea7..848b0efaa 100644 --- a/src/tools/cargo/src/doc/contrib/src/index.md +++ b/src/tools/cargo/src/doc/contrib/src/index.md @@ -5,8 +5,8 @@ overview of how to contribute to Cargo, how to dive into the code, and how the testing infrastructure works. There are many ways to contribute, such as [helping other users], [filing -issues], [improving the documentation], [fixing bugs], and working on [small] -and [large features]. +issues], [improving the documentation], [triaging issues], [fixing bugs], and +working on [small] and [large features]. If you have a general question about Cargo or its internals, feel free to ask on [Zulip]. @@ -24,6 +24,7 @@ Please also read the [Rust Code of Conduct]. [rustup]: https://rust-lang.github.io/rustup/ [git]: https://git-scm.com/ [improving the documentation]: https://github.com/rust-lang/cargo/tree/master/src/doc -[fixing bugs]: process/index.md#working-on-small-bugs +[fixing bugs]: process/index.md#working-on-issues [small]: process/index.md#working-on-small-features [large features]: process/index.md#working-on-large-features +[triaging issues]: issues.md#triaging-issues diff --git a/src/tools/cargo/src/doc/contrib/src/issues.md b/src/tools/cargo/src/doc/contrib/src/issues.md index 8fc69544c..b82492d27 100644 --- a/src/tools/cargo/src/doc/contrib/src/issues.md +++ b/src/tools/cargo/src/doc/contrib/src/issues.md @@ -57,53 +57,184 @@ necessary. ## Issue labels [Issue labels] are very helpful to identify the types of issues and which -category they are related to. The Cargo team typically manages assigning -labels. The labels use a naming convention with short prefixes and colors to -indicate the kind of label: +category they are related to. -* Yellow, **A**-prefixed labels state which **area** of the project an issue - relates to. +Anyone can apply most labels by posting comments with a form such as: -* Light purple, **C**-prefixed labels represent the **category** of an issue. - In particular, **[C-feature-request]** marks *proposals* for new features. If - an issue is **C-feature-request**, but is not **[Feature accepted]** or - **[I-nominated]**, then it was not thoroughly discussed, and might need some - additional design or perhaps should be implemented as an external subcommand - first. Ping @rust-lang/cargo if you want to send a PR for such issue. +```text +@rustbot label: +A-doctests, -A-dependency-resolution +``` -* Dark purple, **Command**-prefixed labels mean the issue has to do with a - specific cargo command. +This example will add the [`A-doctests`] label and remove the +[`A-dependency-resolution`] label. -* Green, **E**-prefixed labels indicate the level of **experience** or - **effort** necessary to fix the issue. **[E-mentor]** issues also - have some instructions on how to get started. Generally, all of the - **E**-prefixed labels are issues that are ready for someone to contribute - to! +[Issue labels]: https://github.com/rust-lang/cargo/labels +[`A-doctests`]: https://github.com/rust-lang/cargo/labels/A-doctests +[`A-dependency-resolution`]: https://github.com/rust-lang/cargo/labels/A-dependency-resolution + +The labels use a naming convention with short prefixes and colors to indicate +the kind of label: + +<style> +.label-color { + border-radius:0.5em; +} +table td:nth-child(2) { + white-space: nowrap; +} + +</style> + +| Labels | Color | Description | +|--------|-------|-------------| +| [A-] | <span class="label-color" style="background-color:#fbca04;"> </span> Yellow | The **area** of the project an issue relates to. | +| [beta-] | <span class="label-color" style="background-color:#1e76d9;"> </span> Dark Blue | Tracks changes which need to be [backported to beta][beta-backport] | +| [C-] | <span class="label-color" style="background-color:#f5f1fd;"> </span> Light Purple | The **category** of an issue. | +| [Command-] | <span class="label-color" style="background-color:#5319e7;"> </span> Dark Purple | The `cargo` command it is related to. | +| [E-] | <span class="label-color" style="background-color:#02e10c;"> </span> Green | The **experience** level necessary to fix an issue. | +| [I-] | <span class="label-color" style="background-color:#fc2929;"> </span> Red | The **importance** of the issue. | +| [O-] | <span class="label-color" style="background-color:#7e7ec8;"> </span> Purple Grey | The **operating system** or platform that the issue is specific to. | +| [P-] | <span class="label-color" style="background-color:#eb6420;"> </span> Orange | The issue **priority**. | +| [regression-] | <span class="label-color" style="background-color:#e4008a;"> </span> Pink | Tracks regressions from a stable release. | +| [relnotes] | <span class="label-color" style="background-color:#fad8c7;"> </span> Light Orange | Marks issues or PRs that should be highlighted in the [Rust release notes] of the next release. | +| [S-] | Varies | Tracks the **status** of issues and pull requests (see [Issue status labels](#issue-status-labels)) | +| [Z-] | <span class="label-color" style="background-color:#453574;"> </span> Dark Blue | Unstable, [nightly features]. | + + +[A-]: https://github.com/rust-lang/cargo/labels?q=A +[beta-]: https://github.com/rust-lang/cargo/labels?q=beta +[beta-backport]: https://forge.rust-lang.org/release/backporting.html#beta-backporting-in-rust-langcargo +[C-]: https://github.com/rust-lang/cargo/labels?q=C +[Command-]: https://github.com/rust-lang/cargo/labels?q=Command +[E-]: https://github.com/rust-lang/cargo/labels?q=E +[I-]: https://github.com/rust-lang/cargo/labels?q=I +[nightly features]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html +[O-]: https://github.com/rust-lang/cargo/labels?q=O +[P-]: https://github.com/rust-lang/cargo/labels?q=P +[regression-]: https://github.com/rust-lang/cargo/labels?q=regression +[relnotes]: https://github.com/rust-lang/cargo/issues?q=label%3Arelnotes +[Rust release notes]: https://github.com/rust-lang/rust/blob/master/RELEASES.md +[S-]: https://github.com/rust-lang/cargo/labels?q=S +[Z-]: https://github.com/rust-lang/cargo/labels?q=nightly -* Red, **I**-prefixed labels indicate the **importance** of the issue. The - **[I-nominated]** label indicates that an issue has been nominated for - prioritizing at the next triage meeting. +### Issue status labels -* Purple gray, **O**-prefixed labels are the **operating system** or platform - that this issue is specific to. +The `S-` prefixed *status* labels are the primary mechanism we use to track +what is happening with an issue and what it is waiting on. The following is a +list of the status labels and what they mean. This is listed roughly in the +order that an issue might go through, though issues will often jump to +different steps, or in rare cases have multiple statuses. -* Orange, **P**-prefixed labels indicate a bug's **priority**. +* **[S-triage]** --- New issues get this label automatically assigned to them + to indicate that nobody has yet looked at them, and they need someone to + assign other labels and decide what the next step is. -* **S**-prefixed labels are "status" labels, typically used for PRs, but can - also indicate an issue is **[S-blocked]**. +* **[S-needs-info]** --- Needs more info, such as a reproduction or more + background for a feature request. -* The light orange **[relnotes]** label marks issues that should be highlighted - in the [Rust release notes] of the next release. + Anyone is welcome to help with providing additional info to help reproduce + or provide more detail on use cases and such. But usually this is a request + to the initial author. -* Dark blue, **Z**-prefixed labels are for unstable, [nightly features]. + When adding this label, there should also usually be a comment that goes + along with it stating the information requested. + +* **[S-needs-team-input]** --- Needs input from team on whether/how to + proceed. + + Here it is essentially blocked waiting for a team member to move it to the + next stage. + +* **[S-needs-design]** --- Needs someone to work further on the design for the + feature or fix. + + Anyone is welcome to help at this stage, but it should be clear that it is + not yet accepted. It is expected that people should contribute comments and + ideas to the issue which furthers the process of fleshing out what is + needed, or alternate ideas. This may also require reaching out to the wider + community via forums and such. + +* **[S-needs-rfc]** --- Needs an [RFC] before this can make more progress. + + Anyone is welcome to help at this stage, but it should be clear that it is + not yet accepted. However, this should only be tagged for changes that are + somewhat likely to be accepted. + +* **[S-needs-mentor]** --- Needs a Cargo team member to commit to helping and + reviewing. + + This is for something that is accepted, such as after an RFC or a team + discussion, or an obvious issue that just needs fixing, but no team member + is available to help or review. + +* **[S-accepted]** --- Issue or feature is accepted, and has a team member + available to help mentor or review. + +* **[S-waiting-on-feedback]** --- An implemented feature is waiting on + community feedback for bugs or design concerns. + + This is typically used on a [tracking issue] after it has been implemented + to indicate what it is waiting on. + + +[S-triage]: https://github.com/rust-lang/cargo/labels/S-triage +[S-needs-info]: https://github.com/rust-lang/cargo/labels/S-needs-info +[S-needs-team-input]: https://github.com/rust-lang/cargo/labels/S-needs-team-input +[S-needs-design]: https://github.com/rust-lang/cargo/labels/S-needs-design +[S-needs-rfc]: https://github.com/rust-lang/cargo/labels/S-needs-rfc +[S-needs-mentor]: https://github.com/rust-lang/cargo/labels/S-needs-mentor +[S-accepted]: https://github.com/rust-lang/cargo/labels/S-accepted +[S-waiting-on-feedback]: https://github.com/rust-lang/cargo/labels/S-waiting-on-feedback +[RFC]: https://github.com/rust-lang/rfcs/ +[tracking issue]: https://github.com/rust-lang/cargo/labels/C-tracking-issue + +## Triaging issues + +Triaging issues involves processing issues to assign appropriate labels, make +sure the issue has sufficient information, and to decide the next steps. +When new issues are filed, they should automatically get the [S-triage] label +assuming the author uses one of the templates. This helps identify which +issues have not yet been triaged. + +There are several things to consider when triaging an issue: + +* Is this a duplicate? Search the issue tracker (including closed issues) to + see if there is something similar or identical to what is reported. If it is + obviously a duplicate, write a comment that it is a duplicate of the other + issue, and close the issue. If it isn't obvious that it is a duplicate, + leave a comment asking the author if the other issue covers what they reported. + +* For a bug, check if the report contains enough information to reproduce it. + If you can't reproduce it, solicit more information from the author to + better understand the issue. + Change the label from [S-triage] to [S-needs-info] if this is the case. + +* Add labels that describe what the issue is related to. + + * Add the appropriate [A-], [Command-], [O-], and [Z-] prefixed labels. + * If this is a regression from stable, add one of the [regression-] + prefixed labels (depending on if it is a regression in an already + released stable release, or it is in nightly). -[Issue labels]: https://github.com/rust-lang/cargo/labels -[E-easy]: https://github.com/rust-lang/cargo/labels/E-easy -[E-mentor]: https://github.com/rust-lang/cargo/labels/E-mentor -[I-nominated]: https://github.com/rust-lang/cargo/labels/I-nominated -[C-feature-request]: https://github.com/rust-lang/cargo/labels/C-feature-request -[Feature accepted]: https://github.com/rust-lang/cargo/labels/Feature%20accepted -[S-blocked]: https://github.com/rust-lang/cargo/labels/S-blocked -[Rust release notes]: https://github.com/rust-lang/rust/blob/master/RELEASES.md -[nightly features]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html -[relnotes]: https://github.com/rust-lang/cargo/issues?q=label%3Arelnotes +* Assuming the issue looks valid, remove the [S-triage] label and move it onto + a new status: + + * [S-needs-rfc] --- This is a large feature request that will require a + public design process. + * [S-needs-design] --- The resolution of the issue or small feature request + will need more work to come up with the appropriate design. + * [S-needs-team-input] --- The next steps are not clear, and the Cargo team + needs to discuss whether or not to proceed and what needs to be done to + address the issue. + * [S-needs-mentor] --- This is something the Cargo team wants to address, + but does not currently have the capacity to help with reviewing. + * [S-accepted] --- This is something that clearly needs to be addressed, and + a Cargo team member has volunteered to help review. + +Anyone is welcome to help with the triaging process. You can help with +reproducing issues, checking for duplicates, gathering more information from +the reporter, assigning labels using [`@rustbot` comments](#issue-labels), and +creating a test using [Cargo's testsuite] ([example][cargotest-example]). + +[Cargo's testsuite]: tests/writing.md +[cargotest-example]: https://github.com/rust-lang/cargo/issues/11628#issuecomment-1411088951 diff --git a/src/tools/cargo/src/doc/contrib/src/process/index.md b/src/tools/cargo/src/doc/contrib/src/process/index.md index 348c49ba9..63f07ca55 100644 --- a/src/tools/cargo/src/doc/contrib/src/process/index.md +++ b/src/tools/cargo/src/doc/contrib/src/process/index.md @@ -15,16 +15,12 @@ reviewed.** [Working on Cargo]: working-on-cargo.md -## Cargo team +## Mentorship -Cargo is managed by a [team] of volunteers. The Cargo Team reviews all -changes, and sets the direction for the project. +Some Cargo team members are available to directly mentor contributions to Cargo. +See the [office hours] page for more information. -The team meets on a weekly basis on a video chat. If you are interested in -participating, feel free to contact us on [Zulip]. - -If you would like more direct mentorship, you can join our -[office hours](https://github.com/rust-lang/cargo/wiki/Office-Hours). +[office hours]: https://github.com/rust-lang/cargo/wiki/Office-Hours ## Roadmap @@ -38,44 +34,40 @@ The [RFC Project Board] is used for tracking [RFCs]. [RFC Project Board]: https://github.com/rust-lang/cargo/projects/2 [RFCs]: https://github.com/rust-lang/rfcs/ -## Working on small bugs +## Working on issues -Issues labeled with the [E-help-wanted], [E-easy], or [E-mentor] [labels] are -typically issues that the Cargo team wants to see addressed, and are -relatively easy to get started with. If you are interested in one of those, -and it has not already been assigned to someone, leave a comment. See [Issue +Issues labeled with the [S-accepted] [label] are typically issues that the +Cargo team wants to see addressed. If you are interested in one of those, and +it has not already been assigned to someone, leave a comment. See [Issue assignment](#issue-assignment) below for assigning yourself. -If there is a specific issue that you are interested in, but it doesn't have -one of the `E-` labels, leave a comment on the issue. If a Cargo team member -has the time to help out, they will respond to help with the next steps. - -[E-help-wanted]: https://github.com/rust-lang/cargo/labels/E-help-wanted -[E-easy]: https://github.com/rust-lang/cargo/labels/E-easy -[E-mentor]: https://github.com/rust-lang/cargo/labels/E-mentor -[labels]: ../issues.md#issue-labels - -## Working on large bugs +When possible, the Cargo team will try to also include [E-easy], [E-medium], +or [E-hard] labels to try to give an estimate of the difficulty involved with +the issue. -Some issues may be difficult to fix. They may require significant code -changes, or major design decisions. The [E-medium] and [E-hard] [labels] can -be used to tag such issues. These will typically involve some discussion with -the Cargo team on how to tackle it. +If there is a specific issue that you are interested in, but it is not marked +as [S-accepted], leave a comment on the issue. If a Cargo team member has the +time to help out, they will respond to help with the next steps. +[E-easy]: https://github.com/rust-lang/cargo/labels/E-easy [E-medium]: https://github.com/rust-lang/cargo/labels/E-medium [E-hard]: https://github.com/rust-lang/cargo/labels/E-hard +[S-accepted]: https://github.com/rust-lang/cargo/labels/S-accepted +[label]: ../issues.md#issue-labels ## Working on small features Small feature requests are typically managed on the [issue tracker][issue-feature-request]. Features that the Cargo team have approved -will have the [Feature accepted] label or the [E-mentor] label. If there is a -feature request that you are interested in, feel free to leave a comment -expressing your interest. If a Cargo team member has the time to help out, -they will respond to help with the next steps. Keep in mind that the Cargo -team has limited time, and may not be able to help with every feature request. -Most of them require some design work, which can be difficult. Check out the -[design principles chapter] for some guidance. +will have the [S-accepted] label. + +If there is a feature request that you are interested in, but it is not marked +as [S-accepted], feel free to leave a comment expressing your interest. If a +Cargo team member has the time to help out, they will respond to help with the +next steps. Keep in mind that the Cargo team has limited time, and may not be +able to help with every feature request. Most of them require some design +work, which can be difficult. Check out the [design principles chapter] for +some guidance. ## Working on large features @@ -114,11 +106,11 @@ The Cargo project uses several bots: ## Issue assignment -Normally, if you plan to work on an issue that has been marked with one of the -`E-` tags or [Feature accepted], it is sufficient just to leave a comment that -you are working on it. We also have a bot that allows you to formally "claim" -an issue by entering the text `@rustbot claim` in a comment. See the -[Assignment] docs on how this works. +Normally, if you plan to work on an issue that has been marked with the +[S-accepted] label, it is sufficient just to leave a comment that you are +working on it. We also have a bot that allows you to formally claim an issue +by entering the text `@rustbot claim` in a comment. See the [Assignment] docs +on how this works. [Assignment]: https://github.com/rust-lang/triagebot/wiki/Assignment diff --git a/src/tools/cargo/src/doc/contrib/src/process/unstable.md b/src/tools/cargo/src/doc/contrib/src/process/unstable.md index d59b9aa34..9b05efc2e 100644 --- a/src/tools/cargo/src/doc/contrib/src/process/unstable.md +++ b/src/tools/cargo/src/doc/contrib/src/process/unstable.md @@ -33,10 +33,30 @@ typically created when a PR is close to being merged, or soon after it is merged. Use the [tracking issue template] when creating a tracking issue. Larger features should also get a new label in the issue tracker so that when -issues are filed, they can be easily tied together. +issues are filed, they can be easily tied together. Typically this would be +one of the `Z-` prefixed labels for nightly features. + +When opening a tracking issue, be sure to also add an `S-` status label to +indicate what needs to happen for it to move forward: + +* [S-needs-mentor] --- The feature isn't yet implemented, and needs a Cargo + team member to commit to helping guide and review the implementation. +* [S-accepted] --- The feature isn't yet implemented, and has a Cargo team + member willing to help review the implementation. +* [S-waiting-on-feedback] --- After the feature has been implemented, this + label indicates that it is waiting on community feedback for bugs or design + concerns. + +Tracking issues may have multiple status labels if necessary, for example if +something is only partially implemented, it may have both +[S-waiting-on-feedback] (for what is implemented) and [S-needs-mentor] or +[S-accepted] to finish the rest of the work. [tracking issue]: https://github.com/rust-lang/cargo/labels/C-tracking-issue [tracking issue template]: https://github.com/rust-lang/cargo/issues/new?labels=C-tracking-issue&template=tracking_issue.md +[S-needs-mentor]: https://github.com/rust-lang/cargo/labels/S-needs-mentor +[S-accepted]: https://github.com/rust-lang/cargo/labels/S-accepted +[S-waiting-on-feedback]: https://github.com/rust-lang/cargo/labels/S-waiting-on-feedback ## Pre-Stabilization diff --git a/src/tools/cargo/src/doc/contrib/src/team.md b/src/tools/cargo/src/doc/contrib/src/team.md new file mode 100644 index 000000000..51b8eeddd --- /dev/null +++ b/src/tools/cargo/src/doc/contrib/src/team.md @@ -0,0 +1,157 @@ +# Cargo Team + +## Mission + +The Cargo Team is a group of volunteers that support the Rust community in developing and maintaining Cargo, the Rust package manager and build tool. +The team is responsible for deciding how Cargo and its related libraries operate and evolve. +The team has a shared responsibility with the [crates.io team] for the design and usage of Cargo's index format and its registry API as it relates to the [crates.io] service. + +The team is expected to keep Cargo in an operational state, to support Rust's 6-week release cycle, and to uphold the [Design Principles] of Cargo. + +[crates.io team]: https://www.rust-lang.org/governance/teams/crates-io +[crates.io]: https://crates.io/ +[Design Principles]: design.md + +## Team membership + +The Cargo Team consists of team members with one serving as a team leader. +The team leader is responsible for coordinating the team and providing a contact point with other teams. +The leader is selected by consensus of the existing members with no objections. + +Membership is maintained in the [Rust team database]. + +[Rust team database]: https://github.com/rust-lang/team/blob/master/teams/cargo.toml + +### Membership expectations + +Team members are expected to participate in voting on RFCs and major change proposals + +Team members are expected to regularly participate in at least some of the following membership-related activities. +Members are not expected to participate in all of these activities, but exhibit some interest and involvement in the project that covers some of these activities. + +- Attending meetings +- Reviewing contributions (auto-assignment is managed in [triagebot.toml]) +- Triaging and responding to issues +- Mentoring new contributors +- Shepherding major changes and RFCs +- Coordinating interaction with other Rust groups and outside interests +- Managing and updating the policies of the Cargo Team itself +- Keeping up with maintenance of the Cargo codebase, ensuring it stays functional and that infrastructure and team processes continue to run smoothly + +Breaks and vacations are welcome and encouraged. +If a member is no longer participating after a few months, they may be asked to step down. + +Members are required to always: + +- Represent the Rust project in a way that upholds the [Rust code of conduct][coc] to a high standard. +- Represent the Cargo Team in a way that upholds the expectations of this charter, and be friendly, welcoming, and constructive with contributors and users. + +Members are given privileges, such as: + +- Merge permissions (bors rights) +- Issue and project management (GitHub permissions) +- Voting and decision making (RFCs, major changes) +- Access to private communications related to team management and security discussions + +[coc]: https://www.rust-lang.org/policies/code-of-conduct +[triagebot.toml]: https://github.com/rust-lang/cargo/blob/master/triagebot.toml + +### Meetings + +The team meets on a weekly basis on a video chat. +If you are interested in participating, feel free to contact us on [Zulip]. + +### Becoming a member + +A contributor can become a member of the Cargo Team by requesting a review or being nominated by one of the existing members. +They can be added by unanimous consent of the team. +The team lead or another member of the team will also confirm with the moderation team that there are no concerns involving the proposed team member. + +Contributors who wish to join the team should exhibit an interest in carrying the design principles of Cargo and participate in some of the activities listed above in [Membership Expectations](#membership-expectations). + +Members may leave at any time, preferably by letting the team know ahead of time. + +## Decision process + +The team uses a consensus-driven process for making decisions ranging from new features and major changes to management of the team itself. +The degree of process is correlated with the degree of change being proposed: + +- Bug fixes, refactorings, documentation updates, and other small changes are usually delegated to a single team member (who is not the author) to approve based on their judgement. + Team members may also solicit feedback from other members or the whole team for any change should they want to gather other perspectives from the team. + + Some examples of what this might cover are: + - Bug fixes that do not introduce backwards-incompatible changes, and adhere to Cargo's expected behavior. + - Addition of new warnings, or other diagnostic changes. + - New or updated documentation. + - Localized refactorings (that is, those that do not have a significant, wide-ranging impact to the usage and maintenance of the codebase). + - Minor or planned changes to Cargo's console output. + - Beta backports that clearly address a regression, and are expected to be low-risk. + - Development of a previously approved unstable feature that matches the expected development of that feature. + +- Small features or changes, large refactorings, or major changes to Cargo's codebase or process require an approval by the team via consensus. + These decisions can be done via the FCP process of [rfcbot], or in an ad-hoc manner such as during a team meeting. + rfcbot FCP requests do not require waiting for the 10-day feedback window if there is a complete team consensus, as this process is mostly aimed at polling the team rather than publicly soliciting feedback. + Though, public feedback is welcome at any time. + + Some examples of what this might cover are: + - Addition of a new, minor command-line argument, or an addition of an option to an existing one. + - Addition of new fields and values to JSON outputs. + - A bug fix or change that may technically involve a backwards-incompatible change. + See the [Backwards compatibility] section for some examples. + - Documentation changes that may substantially change the expected usage of Rust and Cargo. + For example, the [SemVer chapter] contains subjective prescriptions for how users should develop their code. + - A significant change in Cargo's console output. + - A significant change to Cargo's code structure, or how maintenance or usage of the Cargo codebase is handled. + - Beta backports that are risky or have any uncertainty about their necessity. + - [Stable backports]. + These usually also require involvement with the Release team. + - A significant change to the management of the Cargo team itself or the processes it uses, such as significant updates to this document. + - Addition of new members to the Cargo team, or other actions involving the team membership. + These decisions are usually processed via private channels by the entirety of the team. + - A change that is a "one-way door". + That is, something that is difficult to reverse without breaking backwards compatibility. + +- Larger features should usually go through the [RFC process]. + This usually involves first soliciting feedback from the Cargo team and the rest of the community, often via the [Rust Internals] discussion board, [Cargo's issue tracker], and the [Zulip] channel. + If there is positive feedback to the idea, the next step is to formally post an RFC on the RFC repo. + The community and the Cargo team will have an opportunity to provide feedback on the proposal. + After some period of time, the Cargo team may decide to either accept, postpone, or close a proposal based on the interest in the proposal and the team's availability. + + Some examples of what this might cover are: + - Major changes or new features or options in `Cargo.toml` or the config files. + - Changes to the registry index or API. + - New or changed CLI options that are expected to have a significant impact on how Cargo is used. + - New `cargo` commands that are not trivial. + In some cases, the team may decide to adopt a pre-existing external command without an RFC if the command has already been broadly adopted. + +- Stabilization of [Unstable] features requires an approval via the FCP process of [rfcbot]. + This provides a final opportunity to solicit feedback from the public, and for the Cargo team to agree via consensus. + +- The team may decide to experiment with larger features without starting the RFC process if it is an initiative that the team has consensus that it is something they want to pursue. + This is usually reserved for something that has an unclear path that the RFC process is not expected to provide feedback that would substantially move the process forward. + Such experiments are expected to be nightly-only (see the [Unstable] chapter), and involve efforts to shape the final result via exploration, testing, and public involvement. + Any such features *must* ultimately have an RFC approved before they can be stabilized. + +[rfcbot]: https://github.com/rust-lang/rfcbot-rs +[RFC process]: https://github.com/rust-lang/rfcs/ +[Rust Internals]: https://internals.rust-lang.org/ +[Unstable]: process/unstable.md +[Backwards compatibility]: design.md#backwards-compatibility +[Stable backports]: process/release.md#stable-backports +[SemVer chapter]: https://doc.rust-lang.org/cargo/reference/semver.html + +## Contacting the team + +The team may be contacted through several channels: + +- If you have a **security concern**, please refer to Rust's [security policy] for the correct contact method. +- Issues and feature requests can be submitted to [Cargo's issue tracker]. + Please see the [Issues chapter] for more detail. +- The [`t-cargo` Zulip channel][Zulip] stream is the chat platform the Cargo Team uses to coordinate on. +- The <cargo@rust-lang.org> email address can be used to contact the team. + However, using one of the other channels is strongly encouraged. + +[Zulip]: https://rust-lang.zulipchat.com/#narrow/stream/246057-t-cargo +[security policy]: https://www.rust-lang.org/security.html +[Cargo's issue tracker]: https://github.com/rust-lang/cargo/issues/ +[Issues chapter]: issues.md diff --git a/src/tools/cargo/src/doc/man/cargo-add.md b/src/tools/cargo/src/doc/man/cargo-add.md index c441a82b2..3c15fc9d5 100644 --- a/src/tools/cargo/src/doc/man/cargo-add.md +++ b/src/tools/cargo/src/doc/man/cargo-add.md @@ -123,6 +123,15 @@ crates, the features for a specific crate may be enabled with which enables all specified features. {{/option}} +{{#option "`--ignore-rust-version`" }} +Ignore `rust-version` specification in packages. + +This option is unstable and available only on the +[nightly channel](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html) +and requires the `-Z unstable-options` flag to enable. +See <https://github.com/rust-lang/cargo/issues/5579> for more information. +{{/option}} + {{/options}} diff --git a/src/tools/cargo/src/doc/man/cargo-bench.md b/src/tools/cargo/src/doc/man/cargo-bench.md index 80785891b..18771c3d2 100644 --- a/src/tools/cargo/src/doc/man/cargo-bench.md +++ b/src/tools/cargo/src/doc/man/cargo-bench.md @@ -86,11 +86,17 @@ following targets of the selected packages: The default behavior can be changed by setting the `bench` flag for the target in the manifest settings. Setting examples to `bench = true` will build and -run the example as a benchmark. Setting targets to `bench = false` will stop -them from being benchmarked by default. Target selection options that take a -target by name ignore the `bench` flag and will always benchmark the given +run the example as a benchmark, replacing the example's `main` function with +the libtest harness. + +Setting targets to `bench = false` will stop them from being bencharmked by +default. Target selection options that take a target by name (such as +`--example foo`) ignore the `bench` flag and will always benchmark the given target. +See [Configuring a target](../reference/cargo-targets.html#configuring-a-target) +for more information on per-target settings. + {{> options-targets-bin-auto-built }} {{> options-targets }} diff --git a/src/tools/cargo/src/doc/man/cargo-install.md b/src/tools/cargo/src/doc/man/cargo-install.md index 31c3d6048..385ed27c2 100644 --- a/src/tools/cargo/src/doc/man/cargo-install.md +++ b/src/tools/cargo/src/doc/man/cargo-install.md @@ -173,7 +173,7 @@ Directory to install packages into. {{> options-target-dir }} {{#option "`--debug`" }} -Build with the `dev` profile instead the `release` profile. +Build with the `dev` profile instead of the `release` profile. See also the `--profile` option for choosing a specific profile by name. {{/option}} diff --git a/src/tools/cargo/src/doc/man/cargo-metadata.md b/src/tools/cargo/src/doc/man/cargo-metadata.md index 4f9032d56..0027a20b1 100644 --- a/src/tools/cargo/src/doc/man/cargo-metadata.md +++ b/src/tools/cargo/src/doc/man/cargo-metadata.md @@ -212,6 +212,12 @@ The output has the following format: "workspace_members": [ "my-package 0.1.0 (path+file:///path/to/my-package)", ], + /* Array of default members of the workspace. + Each entry is the Package ID for the package. + */ + "workspace_default_members": [ + "my-package 0.1.0 (path+file:///path/to/my-package)", + ], // The resolved dependency graph for the entire workspace. The enabled // features are based on the enabled features for the "current" package. // Inactivated optional dependencies are not listed. diff --git a/src/tools/cargo/src/doc/man/cargo-test.md b/src/tools/cargo/src/doc/man/cargo-test.md index 3dce146e6..49792d6be 100644 --- a/src/tools/cargo/src/doc/man/cargo-test.md +++ b/src/tools/cargo/src/doc/man/cargo-test.md @@ -89,13 +89,20 @@ following targets of the selected packages: The default behavior can be changed by setting the `test` flag for the target in the manifest settings. Setting examples to `test = true` will build and run -the example as a test. Setting targets to `test = false` will stop them from -being tested by default. Target selection options that take a target by name +the example as a test, replacing the example's `main` function with the +libtest harness. If you don't want the `main` function replaced, also include +`harness = false`, in which case the example will be built and executed as-is. + +Setting targets to `test = false` will stop them from being tested by default. +Target selection options that take a target by name (such as `--example foo`) ignore the `test` flag and will always test the given target. Doc tests for libraries may be disabled by setting `doctest = false` for the library in the manifest. +See [Configuring a target](../reference/cargo-targets.html#configuring-a-target) +for more information on per-target settings. + {{> options-targets-bin-auto-built }} {{> options-targets }} diff --git a/src/tools/cargo/src/doc/man/cargo-yank.md b/src/tools/cargo/src/doc/man/cargo-yank.md index 8ad28ef24..946e98c85 100644 --- a/src/tools/cargo/src/doc/man/cargo-yank.md +++ b/src/tools/cargo/src/doc/man/cargo-yank.md @@ -15,9 +15,9 @@ The yank command removes a previously published crate's version from the server's index. This command does not delete any data, and the crate will still be available for download via the registry's download link. -Note that existing crates locked to a yanked version will still be able to -download the yanked version to use it. Cargo will, however, not allow any new -crates to be locked to any yanked version. +Cargo will not use a yanked version for any new project or checkout without a +pre-existing lockfile, and will generate an error if there are no longer +any compatible versions for your crate. This command requires you to be authenticated with either the `--token` option or using {{man "cargo-login" 1}}. @@ -25,6 +25,56 @@ or using {{man "cargo-login" 1}}. If the crate name is not specified, it will use the package name from the current directory. +### How yank works + +For example, the `foo` crate published version `1.5.0` and another crate `bar` +declared a dependency on version `foo = "1.5"`. Now `foo` releases a new, but +not semver compatible, version `2.0.0`, and finds a critical issue with `1.5.0`. +If `1.5.0` is yanked, no new project or checkout without an existing lockfile +will be able to use crate `bar` as it relies on `1.5`. + +In this case, the maintainers of `foo` should first publish a semver compatible +version such as `1.5.1` prior to yanking `1.5.0` so that `bar` and all projects +that depend on `bar` will continue to work. + +As another example, consider a crate `bar` with published versions `1.5.0`, +`1.5.1`, `1.5.2`, `2.0.0` and `3.0.0`. The following table identifies the +versions cargo could use in the absence of a lockfile for different SemVer +requirements, following a given release being yanked: + +| Yanked Version / SemVer requirement | `bar = "1.5.0"` | `bar = "=1.5.0"` | `bar = "2.0.0"` | +|-------------------------------------|-----------------------------------------|------------------|------------------| +| `1.5.0` | Use either `1.5.1` or `1.5.2` | **Return Error** | Use `2.0.0` | +| `1.5.1` | Use either `1.5.0` or `1.5.2` | Use `1.5.0` | Use `2.0.0` | +| `2.0.0` | Use either `1.5.0`, `1.5.1` or `0.22.2` | Use `1.5.0` | **Return Error** | + +### When to yank + +Crates should only be yanked in exceptional circumstances, for example, an +accidental publish, an unintentional SemVer breakages, or a significantly +broken and unusable crate. In the case of security vulnerabilities, [RustSec] +is typically a less disruptive mechanism to inform users and encourage them +to upgrade, and avoids the possibility of significant downstream disruption +irrespective of susceptibility to the vulnerability in question. + +A common workflow is to yank a crate having already published a semver +compatible version, to reduce the probability of preventing dependent +crates from compiling. + +When addressing copyright, licensing, or personal data issues with a published +crate, simply yanking it may not suffice. In such cases, contact the maintainers +of the registry you used. For crates.io, refer to their [policies] and contact +them at <help@crates.io>. + +If credentials have been leaked, the recommended course of action is to revoke +them immediately. Once a crate has been published, it is impossible to determine +if the leaked credentials have been copied. Yanking the crate only prevents new +users from downloading it, but cannot stop those who have already downloaded it +from keeping or even spreading the leaked credentials. + +[RustSec]: https://rustsec.org/ +[policies]: https://crates.io/policies + ## OPTIONS ### Yank Options diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-add.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-add.txt index ac332a44e..6447499dc 100644 --- a/src/tools/cargo/src/doc/man/generated_txt/cargo-add.txt +++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-add.txt @@ -111,6 +111,15 @@ OPTIONS be enabled with package-name/feature-name syntax. This flag may be specified multiple times, which enables all specified features. + --ignore-rust-version + Ignore rust-version specification in packages. + + This option is unstable and available only on the nightly channel + <https://doc.rust-lang.org/book/appendix-07-nightly-rust.html> and + requires the -Z unstable-options flag to enable. See + <https://github.com/rust-lang/cargo/issues/5579> for more + information. + Display Options -v, --verbose Use verbose output. May be specified twice for “very verbose” diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-bench.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-bench.txt index 1ca72d577..9108d6165 100644 --- a/src/tools/cargo/src/doc/man/generated_txt/cargo-bench.txt +++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-bench.txt @@ -120,10 +120,17 @@ OPTIONS The default behavior can be changed by setting the bench flag for the target in the manifest settings. Setting examples to bench = true will - build and run the example as a benchmark. Setting targets to bench = - false will stop them from being benchmarked by default. Target selection - options that take a target by name ignore the bench flag and will always - benchmark the given target. + build and run the example as a benchmark, replacing the example’s main + function with the libtest harness. + + Setting targets to bench = false will stop them from being bencharmked + by default. Target selection options that take a target by name (such as + --example foo) ignore the bench flag and will always benchmark the given + target. + + See Configuring a target + <https://doc.rust-lang.org/cargo/reference/cargo-targets.html#configuring-a-target> + for more information on per-target settings. Binary targets are automatically built if there is an integration test or benchmark being selected to benchmark. This allows an integration diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-install.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-install.txt index a29cdcd46..7aefd3492 100644 --- a/src/tools/cargo/src/doc/man/generated_txt/cargo-install.txt +++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-install.txt @@ -207,8 +207,8 @@ OPTIONS workspace of the local crate unless --target-dir is specified. --debug - Build with the dev profile instead the release profile. See also the - --profile option for choosing a specific profile by name. + Build with the dev profile instead of the release profile. See also + the --profile option for choosing a specific profile by name. --profile name Install with the given profile. See the the reference diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-metadata.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-metadata.txt index be8bed7c6..d9d48fd9a 100644 --- a/src/tools/cargo/src/doc/man/generated_txt/cargo-metadata.txt +++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-metadata.txt @@ -207,6 +207,12 @@ OUTPUT FORMAT "workspace_members": [ "my-package 0.1.0 (path+file:///path/to/my-package)", ], + /* Array of default members of the workspace. + Each entry is the Package ID for the package. + */ + "workspace_default_members": [ + "my-package 0.1.0 (path+file:///path/to/my-package)", + ], // The resolved dependency graph for the entire workspace. The enabled // features are based on the enabled features for the "current" package. // Inactivated optional dependencies are not listed. diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-test.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-test.txt index 3f4ed6072..9e26f8aae 100644 --- a/src/tools/cargo/src/doc/man/generated_txt/cargo-test.txt +++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-test.txt @@ -128,14 +128,23 @@ OPTIONS The default behavior can be changed by setting the test flag for the target in the manifest settings. Setting examples to test = true will - build and run the example as a test. Setting targets to test = false - will stop them from being tested by default. Target selection options - that take a target by name ignore the test flag and will always test the - given target. + build and run the example as a test, replacing the example’s main + function with the libtest harness. If you don’t want the main function + replaced, also include harness = false, in which case the example will + be built and executed as-is. + + Setting targets to test = false will stop them from being tested by + default. Target selection options that take a target by name (such as + --example foo) ignore the test flag and will always test the given + target. Doc tests for libraries may be disabled by setting doctest = false for the library in the manifest. + See Configuring a target + <https://doc.rust-lang.org/cargo/reference/cargo-targets.html#configuring-a-target> + for more information on per-target settings. + Binary targets are automatically built if there is an integration test or benchmark being selected to test. This allows an integration test to execute the binary to exercise and test its behavior. The diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-yank.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-yank.txt index 376d7373c..784e71a1a 100644 --- a/src/tools/cargo/src/doc/man/generated_txt/cargo-yank.txt +++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-yank.txt @@ -13,9 +13,9 @@ DESCRIPTION crate will still be available for download via the registry’s download link. - Note that existing crates locked to a yanked version will still be able - to download the yanked version to use it. Cargo will, however, not allow - any new crates to be locked to any yanked version. + Cargo will not use a yanked version for any new project or checkout + without a pre-existing lockfile, and will generate an error if there are + no longer any compatible versions for your crate. This command requires you to be authenticated with either the --token option or using cargo-login(1). @@ -23,6 +23,62 @@ DESCRIPTION If the crate name is not specified, it will use the package name from the current directory. + How yank works + For example, the foo crate published version 1.5.0 and another crate bar + declared a dependency on version foo = "1.5". Now foo releases a new, + but not semver compatible, version 2.0.0, and finds a critical issue + with 1.5.0. If 1.5.0 is yanked, no new project or checkout without an + existing lockfile will be able to use crate bar as it relies on 1.5. + + In this case, the maintainers of foo should first publish a semver + compatible version such as 1.5.1 prior to yanking 1.5.0 so that bar and + all projects that depend on bar will continue to work. + + As another example, consider a crate bar with published versions 1.5.0, + 1.5.1, 1.5.2, 2.0.0 and 3.0.0. The following table identifies the + versions cargo could use in the absence of a lockfile for different + SemVer requirements, following a given release being yanked: + + +------------------------+----------------------+----------+----------+ + | Yanked Version / | bar = "1.5.0" | bar = | bar = | + | SemVer requirement | | "=1.5.0" | "2.0.0" | + +------------------------+----------------------+----------+----------+ + | 1.5.0 | Use either 1.5.1 or | Return | Use | + | | 1.5.2 | Error | 2.0.0 | + +------------------------+----------------------+----------+----------+ + | 1.5.1 | Use either 1.5.0 or | Use | Use | + | | 1.5.2 | 1.5.0 | 2.0.0 | + +------------------------+----------------------+----------+----------+ + | 2.0.0 | Use either 1.5.0, | Use | Return | + | | 1.5.1 or 0.22.2 | 1.5.0 | Error | + +------------------------+----------------------+----------+----------+ + + When to yank + Crates should only be yanked in exceptional circumstances, for example, + an accidental publish, an unintentional SemVer breakages, or a + significantly broken and unusable crate. In the case of security + vulnerabilities, RustSec <https://rustsec.org/> is typically a less + disruptive mechanism to inform users and encourage them to upgrade, and + avoids the possibility of significant downstream disruption irrespective + of susceptibility to the vulnerability in question. + + A common workflow is to yank a crate having already published a semver + compatible version, to reduce the probability of preventing dependent + crates from compiling. + + When addressing copyright, licensing, or personal data issues with a + published crate, simply yanking it may not suffice. In such cases, + contact the maintainers of the registry you used. For crates.io, refer + to their policies <https://crates.io/policies> and contact them at + <help@crates.io>. + + If credentials have been leaked, the recommended course of action is to + revoke them immediately. Once a crate has been published, it is + impossible to determine if the leaked credentials have been copied. + Yanking the crate only prevents new users from downloading it, but + cannot stop those who have already downloaded it from keeping or even + spreading the leaked credentials. + OPTIONS Yank Options --vers version, --version version diff --git a/src/tools/cargo/src/doc/src/commands/cargo-add.md b/src/tools/cargo/src/doc/src/commands/cargo-add.md index 89c1cc6f1..132c09326 100644 --- a/src/tools/cargo/src/doc/src/commands/cargo-add.md +++ b/src/tools/cargo/src/doc/src/commands/cargo-add.md @@ -129,6 +129,14 @@ crates, the features for a specific crate may be enabled with which enables all specified features.</dd> +<dt class="option-term" id="option-cargo-add---ignore-rust-version"><a class="option-anchor" href="#option-cargo-add---ignore-rust-version"></a><code>--ignore-rust-version</code></dt> +<dd class="option-desc">Ignore <code>rust-version</code> specification in packages.</p> +<p>This option is unstable and available only on the +<a href="https://doc.rust-lang.org/book/appendix-07-nightly-rust.html">nightly channel</a> +and requires the <code>-Z unstable-options</code> flag to enable. +See <a href="https://github.com/rust-lang/cargo/issues/5579">https://github.com/rust-lang/cargo/issues/5579</a> for more information.</dd> + + </dl> diff --git a/src/tools/cargo/src/doc/src/commands/cargo-bench.md b/src/tools/cargo/src/doc/src/commands/cargo-bench.md index e7e9b36fb..df0101be5 100644 --- a/src/tools/cargo/src/doc/src/commands/cargo-bench.md +++ b/src/tools/cargo/src/doc/src/commands/cargo-bench.md @@ -143,11 +143,17 @@ following targets of the selected packages: The default behavior can be changed by setting the `bench` flag for the target in the manifest settings. Setting examples to `bench = true` will build and -run the example as a benchmark. Setting targets to `bench = false` will stop -them from being benchmarked by default. Target selection options that take a -target by name ignore the `bench` flag and will always benchmark the given +run the example as a benchmark, replacing the example's `main` function with +the libtest harness. + +Setting targets to `bench = false` will stop them from being bencharmked by +default. Target selection options that take a target by name (such as +`--example foo`) ignore the `bench` flag and will always benchmark the given target. +See [Configuring a target](../reference/cargo-targets.html#configuring-a-target) +for more information on per-target settings. + Binary targets are automatically built if there is an integration test or benchmark being selected to benchmark. This allows an integration test to execute the binary to exercise and test its behavior. diff --git a/src/tools/cargo/src/doc/src/commands/cargo-install.md b/src/tools/cargo/src/doc/src/commands/cargo-install.md index 99697c156..5d413010c 100644 --- a/src/tools/cargo/src/doc/src/commands/cargo-install.md +++ b/src/tools/cargo/src/doc/src/commands/cargo-install.md @@ -238,7 +238,7 @@ is specified.</dd> <dt class="option-term" id="option-cargo-install---debug"><a class="option-anchor" href="#option-cargo-install---debug"></a><code>--debug</code></dt> -<dd class="option-desc">Build with the <code>dev</code> profile instead the <code>release</code> profile. +<dd class="option-desc">Build with the <code>dev</code> profile instead of the <code>release</code> profile. See also the <code>--profile</code> option for choosing a specific profile by name.</dd> diff --git a/src/tools/cargo/src/doc/src/commands/cargo-metadata.md b/src/tools/cargo/src/doc/src/commands/cargo-metadata.md index ebde0ea10..e9aeac7df 100644 --- a/src/tools/cargo/src/doc/src/commands/cargo-metadata.md +++ b/src/tools/cargo/src/doc/src/commands/cargo-metadata.md @@ -212,6 +212,12 @@ The output has the following format: "workspace_members": [ "my-package 0.1.0 (path+file:///path/to/my-package)", ], + /* Array of default members of the workspace. + Each entry is the Package ID for the package. + */ + "workspace_default_members": [ + "my-package 0.1.0 (path+file:///path/to/my-package)", + ], // The resolved dependency graph for the entire workspace. The enabled // features are based on the enabled features for the "current" package. // Inactivated optional dependencies are not listed. diff --git a/src/tools/cargo/src/doc/src/commands/cargo-test.md b/src/tools/cargo/src/doc/src/commands/cargo-test.md index 2967d7381..24fcc70ff 100644 --- a/src/tools/cargo/src/doc/src/commands/cargo-test.md +++ b/src/tools/cargo/src/doc/src/commands/cargo-test.md @@ -146,13 +146,20 @@ following targets of the selected packages: The default behavior can be changed by setting the `test` flag for the target in the manifest settings. Setting examples to `test = true` will build and run -the example as a test. Setting targets to `test = false` will stop them from -being tested by default. Target selection options that take a target by name +the example as a test, replacing the example's `main` function with the +libtest harness. If you don't want the `main` function replaced, also include +`harness = false`, in which case the example will be built and executed as-is. + +Setting targets to `test = false` will stop them from being tested by default. +Target selection options that take a target by name (such as `--example foo`) ignore the `test` flag and will always test the given target. Doc tests for libraries may be disabled by setting `doctest = false` for the library in the manifest. +See [Configuring a target](../reference/cargo-targets.html#configuring-a-target) +for more information on per-target settings. + Binary targets are automatically built if there is an integration test or benchmark being selected to test. This allows an integration test to execute the binary to exercise and test its behavior. diff --git a/src/tools/cargo/src/doc/src/commands/cargo-yank.md b/src/tools/cargo/src/doc/src/commands/cargo-yank.md index 18565d2dc..7fac5bf47 100644 --- a/src/tools/cargo/src/doc/src/commands/cargo-yank.md +++ b/src/tools/cargo/src/doc/src/commands/cargo-yank.md @@ -15,9 +15,9 @@ The yank command removes a previously published crate's version from the server's index. This command does not delete any data, and the crate will still be available for download via the registry's download link. -Note that existing crates locked to a yanked version will still be able to -download the yanked version to use it. Cargo will, however, not allow any new -crates to be locked to any yanked version. +Cargo will not use a yanked version for any new project or checkout without a +pre-existing lockfile, and will generate an error if there are no longer +any compatible versions for your crate. This command requires you to be authenticated with either the `--token` option or using [cargo-login(1)](cargo-login.html). @@ -25,6 +25,56 @@ or using [cargo-login(1)](cargo-login.html). If the crate name is not specified, it will use the package name from the current directory. +### How yank works + +For example, the `foo` crate published version `1.5.0` and another crate `bar` +declared a dependency on version `foo = "1.5"`. Now `foo` releases a new, but +not semver compatible, version `2.0.0`, and finds a critical issue with `1.5.0`. +If `1.5.0` is yanked, no new project or checkout without an existing lockfile +will be able to use crate `bar` as it relies on `1.5`. + +In this case, the maintainers of `foo` should first publish a semver compatible +version such as `1.5.1` prior to yanking `1.5.0` so that `bar` and all projects +that depend on `bar` will continue to work. + +As another example, consider a crate `bar` with published versions `1.5.0`, +`1.5.1`, `1.5.2`, `2.0.0` and `3.0.0`. The following table identifies the +versions cargo could use in the absence of a lockfile for different SemVer +requirements, following a given release being yanked: + +| Yanked Version / SemVer requirement | `bar = "1.5.0"` | `bar = "=1.5.0"` | `bar = "2.0.0"` | +|-------------------------------------|-----------------------------------------|------------------|------------------| +| `1.5.0` | Use either `1.5.1` or `1.5.2` | **Return Error** | Use `2.0.0` | +| `1.5.1` | Use either `1.5.0` or `1.5.2` | Use `1.5.0` | Use `2.0.0` | +| `2.0.0` | Use either `1.5.0`, `1.5.1` or `0.22.2` | Use `1.5.0` | **Return Error** | + +### When to yank + +Crates should only be yanked in exceptional circumstances, for example, an +accidental publish, an unintentional SemVer breakages, or a significantly +broken and unusable crate. In the case of security vulnerabilities, [RustSec] +is typically a less disruptive mechanism to inform users and encourage them +to upgrade, and avoids the possibility of significant downstream disruption +irrespective of susceptibility to the vulnerability in question. + +A common workflow is to yank a crate having already published a semver +compatible version, to reduce the probability of preventing dependent +crates from compiling. + +When addressing copyright, licensing, or personal data issues with a published +crate, simply yanking it may not suffice. In such cases, contact the maintainers +of the registry you used. For crates.io, refer to their [policies] and contact +them at <help@crates.io>. + +If credentials have been leaked, the recommended course of action is to revoke +them immediately. Once a crate has been published, it is impossible to determine +if the leaked credentials have been copied. Yanking the crate only prevents new +users from downloading it, but cannot stop those who have already downloaded it +from keeping or even spreading the leaked credentials. + +[RustSec]: https://rustsec.org/ +[policies]: https://crates.io/policies + ## OPTIONS ### Yank Options diff --git a/src/tools/cargo/src/doc/src/faq.md b/src/tools/cargo/src/doc/src/faq.md index 8a8840b8f..abe90c000 100644 --- a/src/tools/cargo/src/doc/src/faq.md +++ b/src/tools/cargo/src/doc/src/faq.md @@ -98,9 +98,9 @@ Yes! All commits to Cargo are required to pass the local test suite on Windows. If you encounter an issue while running on Windows, we consider it a bug, so [please file an -issue][3]. +issue][cargo-issues]. -[3]: https://github.com/rust-lang/cargo/issues +[cargo-issues]: https://github.com/rust-lang/cargo/issues ### Why do binaries have `Cargo.lock` in version control, but not libraries? diff --git a/src/tools/cargo/src/doc/src/reference/manifest.md b/src/tools/cargo/src/doc/src/reference/manifest.md index 49d5b96c6..5a3d60ccc 100644 --- a/src/tools/cargo/src/doc/src/reference/manifest.md +++ b/src/tools/cargo/src/doc/src/reference/manifest.md @@ -203,7 +203,8 @@ description = "A short description of my package" The `documentation` field specifies a URL to a website hosting the crate's documentation. If no URL is specified in the manifest file, [crates.io] will -automatically link your crate to the corresponding [docs.rs] page. +automatically link your crate to the corresponding [docs.rs] page when the +documentation has been built and is available (see [docs.rs queue]). ```toml [package] @@ -211,6 +212,8 @@ automatically link your crate to the corresponding [docs.rs] page. documentation = "https://docs.rs/bitflags" ``` +[docs.rs queue]: https://docs.rs/releases/queue + #### The `readme` field The `readme` field should be the path to a file in the package root (relative diff --git a/src/tools/cargo/src/doc/src/reference/profiles.md b/src/tools/cargo/src/doc/src/reference/profiles.md index 56c8538f8..124203d55 100644 --- a/src/tools/cargo/src/doc/src/reference/profiles.md +++ b/src/tools/cargo/src/doc/src/reference/profiles.md @@ -67,14 +67,20 @@ amount of debug information included in the compiled binary. The valid options are: -* `0` or `false`: no debug info at all -* `1`: line tables only -* `2` or `true`: full debug info +* `0`, `false`, or `"none"`: no debug info at all, default for [`release`](#release) +* `"line-directives-only"`: line info directives only. For the nvptx* targets this enables [profiling]. For other use cases, `line-tables-only` is the better, more compatible choice. +* `"line-tables-only"`: line tables only. Generates the minimal amount of debug info for backtraces with filename/line number info, but not anything else, i.e. no variable or function parameter info. +* `1` or `"limited"`: debug info without type or variable-level information. Generates more detailed module-level info than `line-tables-only`. +* `2`, `true`, or `"full"`: full debug info, default for [`dev`](#dev) + +For more information on what each option does see `rustc`'s docs on [debuginfo]. You may wish to also configure the [`split-debuginfo`](#split-debuginfo) option depending on your needs as well. [`-C debuginfo` flag]: ../../rustc/codegen-options/index.html#debuginfo +[debuginfo]: ../../rustc/codegen-options/index.html#debuginfo +[profiling]: https://reviews.llvm.org/D46061 #### split-debuginfo diff --git a/src/tools/cargo/src/doc/src/reference/publishing.md b/src/tools/cargo/src/doc/src/reference/publishing.md index 98d572c34..564dfb34e 100644 --- a/src/tools/cargo/src/doc/src/reference/publishing.md +++ b/src/tools/cargo/src/doc/src/reference/publishing.md @@ -12,10 +12,10 @@ limit to the number of versions which can be published, however. First things first, you’ll need an account on [crates.io] to acquire an API token. To do so, [visit the home page][crates.io] and log in via a GitHub -account (required for now). You will also need to verify your email address on the -[Account Settings](https://crates.io/me) page. Once that is done create an API token, -make sure you copy it. Once you leave the page you will not be able to see it -again. +account (required for now). You will also need to provide and verify your email +address on the [Account Settings](https://crates.io/settings/profile) page. Once +that is done [create an API token](https://crates.io/settings/tokens), make sure +you copy it. Once you leave the page you will not be able to see it again. Then run the [`cargo login`] command. diff --git a/src/tools/cargo/src/doc/src/reference/registry-index.md b/src/tools/cargo/src/doc/src/reference/registry-index.md index 38e3dd5fe..9e5be3e5b 100644 --- a/src/tools/cargo/src/doc/src/reference/registry-index.md +++ b/src/tools/cargo/src/doc/src/reference/registry-index.md @@ -199,6 +199,9 @@ explaining the format of the entry. "features2": { "serde": ["dep:serde", "chrono?/serde"] } + // The minimal supported Rust version (optional) + // This must be a valid version requirement without an operator (e.g. no `=`) + "rust_version": "1.60" } ``` @@ -221,6 +224,8 @@ The JSON objects should not be modified after they are added except for the > * The publish API includes several other fields, such as `description` and `readme`, which don't appear in the index. > These are intended to make it easier for a registry to obtain the metadata about the crate to display on a website without needing to extract and parse the `.crate` file. > This additional information is typically added to a database on the registry server. +> * Although `rust_version` is included here, [crates.io] will ignore this field +> and instead read it from the `Cargo.toml` contained in the `.crate` file. > > For [`cargo metadata`], the differences are: > diff --git a/src/tools/cargo/src/doc/src/reference/registry-web-api.md b/src/tools/cargo/src/doc/src/reference/registry-web-api.md index 147ababd5..8260028c0 100644 --- a/src/tools/cargo/src/doc/src/reference/registry-web-api.md +++ b/src/tools/cargo/src/doc/src/reference/registry-web-api.md @@ -161,7 +161,10 @@ considered as an exhaustive list of restrictions [crates.io] imposes. }, // The `links` string value from the package's manifest, or null if not // specified. This field is optional and defaults to null. - "links": null + "links": null, + // The minimal supported Rust version (optional) + // This must be a valid version requirement without an operator (e.g. no `=`) + "rust_version": null } ``` @@ -305,6 +308,8 @@ A successful response includes the JSON object: { // Indicates the remove succeeded, always true. "ok": true + // A string to be displayed to the user. Currently ignored by cargo. + "msg": "owners successfully removed", } ``` diff --git a/src/tools/cargo/src/doc/src/reference/semver.md b/src/tools/cargo/src/doc/src/reference/semver.md index 22c42610f..5a53a6554 100644 --- a/src/tools/cargo/src/doc/src/reference/semver.md +++ b/src/tools/cargo/src/doc/src/reference/semver.md @@ -88,8 +88,10 @@ considered incompatible. * [Possibly-breaking: introducing a new function type parameter](#fn-generic-new) * [Minor: generalizing a function to use generics (supporting original type)](#fn-generalize-compatible) * [Major: generalizing a function to use generics with type mismatch](#fn-generalize-mismatch) + * [Minor: making an `unsafe` function safe](#fn-unsafe-safe) * Attributes * [Major: switching from `no_std` support to requiring `std`](#attr-no-std-to-std) + * [Major: adding `non_exhaustive` to an existing enum, variant, or struct with no private fields](#attr-adding-non-exhaustive) * Tooling and environment compatibility * [Possibly-breaking: changing the minimum version of Rust required](#env-new-rust) * [Possibly-breaking: changing the platform and environment requirements](#env-change-requirements) @@ -870,7 +872,7 @@ fn main() { It is safe to change a generic type to a more generic one. For example, the following adds a generic parameter that defaults to the original type, which is safe because all existing users will be using the same type for both -fields, the the defaulted parameter does not need to be specified. +fields, the defaulted parameter does not need to be specified. ```rust,ignore // MINOR CHANGE @@ -1079,6 +1081,47 @@ fn main() { } ``` +<a id="fn-unsafe-safe"></a> +### Minor: making an `unsafe` function safe + +A previously `unsafe` function can be made safe without breaking code. + +Note however that it may cause the [`unused_unsafe`][unused_unsafe] lint to +trigger as in the example below, which will cause local crates that have +specified `#![deny(warnings)]` to stop compiling. Per [introducing new +lints](#new-lints), it is allowed for updates to introduce new warnings. + +Going the other way (making a safe function `unsafe`) is a breaking change. + +```rust,ignore +// MINOR CHANGE + +/////////////////////////////////////////////////////////// +// Before +pub unsafe fn foo() {} + +/////////////////////////////////////////////////////////// +// After +pub fn foo() {} + +/////////////////////////////////////////////////////////// +// Example use of the library that will trigger a lint. +use updated_crate::foo; + +unsafe fn bar(f: unsafe fn()) { + f() +} + +fn main() { + unsafe { foo() }; // The `unused_unsafe` lint will trigger here + unsafe { bar(foo) }; +} +``` + +Making a previously `unsafe` associated function or method on structs / enums +safe is also a minor change, while the same is not true for associated +function on traits (see [any change to trait item signatures](#trait-item-signature)). + <a id="attr-no-std-to-std"></a> ### Major: switching from `no_std` support to requiring `std` @@ -1115,6 +1158,89 @@ Mitigation strategies: optionally enables `std` support, and when the feature is off, the library can be used in a `no_std` environment. +<a id="attr-adding-non-exhaustive"></a> +### Major: adding `non_exhaustive` to an existing enum, variant, or struct with no private fields + +Making items [`#[non_exhaustive]`][non_exhaustive] changes how they may +be used outside the crate where they are defined: + +- Non-exhaustive structs and enum variants cannot be constructed + using [struct literal] syntax, including [functional update syntax]. +- Pattern matching on non-exhaustive structs requires `..` and + matching on enums does not count towards exhaustiveness. +- Casting enum variants to their discriminant with `as` is not allowed. + +Structs with private fields cannot be constructed using [struct literal] syntax +regardless of whether [`#[non_exhaustive]`][non_exhaustive] is used. +Adding [`#[non_exhaustive]`][non_exhaustive] to such a struct is not +a breaking change. + +```rust,ignore +// MAJOR CHANGE + +/////////////////////////////////////////////////////////// +// Before +pub struct Foo { + pub bar: usize, +} + +pub enum Bar { + X, + Y(usize), + Z { a: usize }, +} + +pub enum Quux { + Var, +} + +/////////////////////////////////////////////////////////// +// After +#[non_exhaustive] +pub struct Foo { + pub bar: usize, +} + +pub enum Bar { + #[non_exhaustive] + X, + + #[non_exhaustive] + Y(usize), + + #[non_exhaustive] + Z { a: usize }, +} + +#[non_exhaustive] +pub enum Quux { + Var, +} + +/////////////////////////////////////////////////////////// +// Example usage that will break. +use updated_crate::{Bar, Foo, Quux}; + +fn main() { + let foo = Foo { bar: 0 }; // Error: cannot create non-exhaustive struct using struct expression + + let bar_x = Bar::X; // Error: unit variant `X` is private + let bar_y = Bar::Y(0); // Error: tuple variant `Y` is private + let bar_z = Bar::Z { a: 0 }; // Error: cannot create non-exhaustive variant using struct expression + + let q = Quux::Var; + match q { + Quux::Var => 0, + // Error: non-exhaustive patterns: `_` not covered + }; +} +``` + +Mitigation strategies: +* Mark structs, enums, and enum variants as + [`#[non_exhaustive]`][non_exhaustive] when first introducing them, + rather than adding [`#[non_exhaustive]`][non_exhaustive] later on. + ## Tooling and environment compatibility <a id="env-new-rust"></a> @@ -1125,7 +1251,8 @@ projects that are using older versions of Rust. This also includes using new features in a new release of Cargo, and requiring the use of a nightly-only feature in a crate that previously worked on stable. -Some projects choose to allow this in a minor release for various reasons. It +It is generally recommended to treat this as a minor change, rather than as +a major change, for [various reasons][msrv-is-minor]. It is usually relatively easy to update to a newer version of Rust. Rust also has a rapid 6-week release cycle, and some projects will provide compatibility within a window of releases (such as the current stable release plus N @@ -1393,6 +1520,7 @@ document what your commitments are. [Default]: ../../std/default/trait.Default.html [deprecated]: ../../reference/attributes/diagnostics.html#the-deprecated-attribute [disambiguation syntax]: ../../reference/expressions/call-expr.html#disambiguating-function-calls +[functional update syntax]: ../../reference/expressions/struct-expr.html#functional-update-syntax [inherent implementations]: ../../reference/items/implementations.html#inherent-implementations [items]: ../../reference/items.html [non_exhaustive]: ../../reference/attributes/type_system.html#the-non_exhaustive-attribute @@ -1402,3 +1530,5 @@ document what your commitments are. [SemVer]: https://semver.org/ [struct literal]: ../../reference/expressions/struct-expr.html [wildcard patterns]: ../../reference/patterns.html#wildcard-pattern +[unused_unsafe]: ../../rustc/lints/listing/warn-by-default.html#unused-unsafe +[msrv-is-minor]: https://github.com/rust-lang/api-guidelines/discussions/231 diff --git a/src/tools/cargo/src/doc/src/reference/unstable.md b/src/tools/cargo/src/doc/src/reference/unstable.md index accd45d8e..7484db9b5 100644 --- a/src/tools/cargo/src/doc/src/reference/unstable.md +++ b/src/tools/cargo/src/doc/src/reference/unstable.md @@ -69,6 +69,7 @@ Each new feature described below should explain how to use it. * [minimal-versions](#minimal-versions) --- Forces the resolver to use the lowest compatible version instead of the highest. * [direct-minimal-versions](#direct-minimal-versions) — Forces the resolver to use the lowest compatible version instead of the highest. * [public-dependency](#public-dependency) --- Allows dependencies to be classified as either public or private. + * [msrv-policy](#msrv-policy) --- MSRV-aware resolver and version selection * Output behavior * [out-dir](#out-dir) --- Adds a directory where artifacts are copied to. * [Different binary name](#different-binary-name) --- Assign a name to the built binary that is separate from the crate name. @@ -92,6 +93,7 @@ Each new feature described below should explain how to use it. * [codegen-backend](#codegen-backend) --- Select the codegen backend used by rustc. * [per-package-target](#per-package-target) --- Sets the `--target` to use for each individual package. * [artifact dependencies](#artifact-dependencies) --- Allow build artifacts to be included into other build artifacts and build them for different targets. + * [`[lints]`](#lints) --- Configure lint levels for various linter tools. * Information and metadata * [Build-plan](#build-plan) --- Emits JSON information on which commands will be run. * [unit-graph](#unit-graph) --- Emits JSON for Cargo's internal graph structure. @@ -300,6 +302,14 @@ my_dep = { version = "1.2.3", public = true } private_dep = "2.0.0" # Will be 'private' by default ``` +### msrv-policy +- [#9930](https://github.com/rust-lang/cargo/issues/9930) (MSRV-aware resolver) +- [#10653](https://github.com/rust-lang/cargo/issues/10653) (MSRV-aware cargo-add) +- [#10903](https://github.com/rust-lang/cargo/issues/10903) (MSRV-aware cargo-install) + +The `msrv-policy` feature enables experiments in MSRV-aware policy for cargo in +preparation for an upcoming RFC. + ### build-std * Tracking Repository: <https://github.com/rust-lang/wg-cargo-std-aware> @@ -772,12 +782,120 @@ the command line) target. * Tracking Issue: [#9096](https://github.com/rust-lang/cargo/pull/9096) * Original Pull Request: [#9992](https://github.com/rust-lang/cargo/pull/9992) -Allow Cargo packages to depend on `bin`, `cdylib`, and `staticlib` crates, +Artifact dependencies allow Cargo packages to depend on `bin`, `cdylib`, and `staticlib` crates, and use the artifacts built by those crates at compile time. Run `cargo` with `-Z bindeps` to enable this functionality. -**Example:** use _cdylib_ artifact in build script +#### artifact-dependencies: Dependency declarations + +Artifact-dependencies adds the following keys to a dependency declaration in `Cargo.toml`: + +- `artifact` --- This specifies the [Cargo Target](cargo-targets.md) to build. + Normally without this field, Cargo will only build the `[lib]` target from a dependency. + This field allows specifying which target will be built, and made available as a binary at build time: + + * `"bin"` --- Compiled executable binaries, corresponding to all of the `[[bin]]` sections in the dependency's manifest. + * `"bin:<bin-name>"` --- Compiled executable binary, corresponding to a specific binary target specified by the given `<bin-name>`. + * `"cdylib"` --- A C-compatible dynamic library, corresponding to a `[lib]` section with `crate-type = ["cdylib"]` in the dependency's manifest. + * `"staticlib"` --- A C-compatible static library, corresponding to a `[lib]` section with `crate-type = ["staticlib"]` in the dependency's manifest. + + The `artifact` value can be a string, or it can be an array of strings to specify multiple targets. + + Example: + + ```toml + [dependencies] + bar = { version = "1.0", artifact = "staticlib" } + zoo = { version = "1.0", artifact = ["bin:cat", "bin:dog"]} + ``` + +- `lib` --- This is a Boolean value which indicates whether or not to also build the dependency's library as a normal Rust `lib` dependency. + This field can only be specified when `artifact` is specified. + + The default for this field is `false` when `artifact` is specified. + If this is set to `true`, then the dependency's `[lib]` target will also be built for the platform target the declaring package is being built for. + This allows the package to use the dependency from Rust code like a normal dependency in addition to an artifact dependency. + + Example: + + ```toml + [dependencies] + bar = { version = "1.0", artifact = "bin", lib = true } + ``` + +- `target` --- The platform target to build the dependency for. + This field can only be specified when `artifact` is specified. + + The default if this is not specified depends on the dependency kind. + For build dependencies, it will be built for the host target. + For all other dependencies, it will be built for the same targets the declaring package is built for. + + For a build dependency, this can also take the special value of `"target"` which means to build the dependency for the same targets that the package is being built for. + + ```toml + [build-dependencies] + bar = { version = "1.0", artifact = "cdylib", target = "wasm32-unknown-unknown"} + same-target = { version = "1.0", artifact = "bin", target = "target" } + ``` + +#### artifact-dependencies: Environment variables + +After building an artifact dependency, Cargo provides the following environment variables that you can use to access the artifact: + +- `CARGO_<ARTIFACT-TYPE>_DIR_<DEP>` --- This is the directory containing all the artifacts from the dependency. + + `<ARTIFACT-TYPE>` is the `artifact` specified for the dependency (uppercased as in `CDYLIB`, `STATICLIB`, or `BIN`) and `<DEP>` is the name of the dependency. + As with other Cargo environment variables, dependency names are converted to uppercase, with dashes replaced by underscores. + + If your manifest renames the dependency, `<DEP>` corresponds to the name you specify, not the original package name. + +- `CARGO_<ARTIFACT-TYPE>_FILE_<DEP>_<NAME>` --- This is the full path to the artifact. + + `<ARTIFACT-TYPE>` is the `artifact` specified for the dependency (uppercased as above), `<DEP>` is the name of the dependency (transformed as above), and `<NAME>` is the name of the artifact from the dependency. + + Note that `<NAME>` is not modified in any way from the `name` specified in the crate supplying the artifact, or the crate name if not specified; for instance, it may be in lowercase, or contain dashes. + + For convenience, if the artifact name matches the original package name, cargo additionally supplies a copy of this variable with the `_<NAME>` suffix omitted. + For instance, if the `cmake` crate supplies a binary named `cmake`, Cargo supplies both `CARGO_BIN_FILE_CMAKE` and `CARGO_BIN_FILE_CMAKE_cmake`. + +For each kind of dependency, these variables are supplied to the same part of the build process that has access to that kind of dependency: + +- For build-dependencies, these variables are supplied to the `build.rs` script, and can be accessed using [`std::env::var_os`](https://doc.rust-lang.org/std/env/fn.var_os.html). + (As with any OS file path, these may or may not be valid UTF-8.) +- For normal dependencies, these variables are supplied during the compilation of the crate, and can be accessed using the [`env!`] macro. +- For dev-dependencies, these variables are supplied during the compilation of examples, tests, and benchmarks, and can be accessed using the [`env!`] macro. + +[`env!`]: https://doc.rust-lang.org/std/macro.env.html + +#### artifact-dependencies: Examples + +##### Example: use a binary executable from a build script + +In the `Cargo.toml` file, you can specify a dependency on a binary to make available for a build script: + +```toml +[build-dependencies] +some-build-tool = { version = "1.0", artifact = "bin" } +``` + +Then inside the build script, the binary can be executed at build time: + +```rust +fn main() { + let build_tool = std::env::var_os("CARGO_BIN_FILE_SOME_BUILD_TOOL").unwrap(); + let status = std::process::Command::new(build_tool) + .arg("do-stuff") + .status() + .unwrap(); + if !status.success() { + eprintln!("failed!"); + std::process::exit(1); + } +} +``` + +##### Example: use _cdylib_ artifact in build script The `Cargo.toml` in the consuming package, building the `bar` library as `cdylib` for a specific build target… @@ -791,11 +909,11 @@ bar = { artifact = "cdylib", version = "1.0", target = "wasm32-unknown-unknown" ```rust fn main() { - wasm::run_file(std::env::var("CARGO_CDYLIB_FILE_BAR").unwrap()); + wasm::run_file(std::env::var("CARGO_CDYLIB_FILE_BAR").unwrap()); } ``` -**Example:** use _binary_ artifact and its library in a binary +##### Example: use _binary_ artifact and its library in a binary The `Cargo.toml` in the consuming package, building the `bar` binary for inclusion as artifact while making it available as library as well… @@ -809,8 +927,8 @@ bar = { artifact = "bin", version = "1.0", lib = true } ```rust fn main() { - bar::init(); - command::run(env!("CARGO_BIN_FILE_BAR")); + bar::init(); + command::run(env!("CARGO_BIN_FILE_BAR")); } ``` @@ -1251,7 +1369,7 @@ codegen-backend = "cranelift" * Tracking Issue: [#11813](https://github.com/rust-lang/cargo/issues/11813) -With the 'gitoxide' unstable feature, all or the the specified git operations will be performed by +With the 'gitoxide' unstable feature, all or the specified git operations will be performed by the `gitoxide` crate instead of `git2`. While `-Zgitoxide` enables all currently implemented features, one can individually select git operations @@ -1260,10 +1378,114 @@ to run with `gitoxide` with the `-Zgitoxide=operation[,operationN]` syntax. Valid operations are the following: * `fetch` - All fetches are done with `gitoxide`, which includes git dependencies as well as the crates index. -* `shallow-index` *(planned)* - perform a shallow clone of the index. -* `shallow-deps` *(planned)* - perform a shallow clone of git dependencies. +* `shallow-index` - perform a shallow clone of the index. +* `shallow-deps` - perform a shallow clone of git dependencies. * `checkout` *(planned)* - checkout the worktree, with support for filters and submodules. +**Details on shallow clones** + +* To enable shallow clones, add `-Zgitoxide=fetch,shallow_deps` for fetching git dependencies or `-Zgitoxide=fetch,shallow_index` for fetching registry index. +* Shallow-cloned and shallow-checked-out git repositories reside at their own `-shallow` suffixed directories, i.e, + - `~/.cargo/registry/index/*-shallow` + - `~/.cargo/git/db/*-shallow` + - `~/.cargo/git/checkouts/*-shallow` +* When the unstable feature is on, fetching/cloning a git repository is always a shallow fetch. This roughly equals to `git fetch --depth 1` everywhere. +* Even with the presence of `Cargo.lock` or specifying a commit `{ rev = "…" }`, gitoxide is still smart enough to shallow fetch without unshallowing the existing repository. + +### `[lints]` + +* Tracking Issue: [#12115](https://github.com/rust-lang/cargo/issues/12115) + +A new `lints` table would be added to configure lints: +```toml +[lints.rust] +unsafe = "forbid" +``` +and `cargo` would pass these along as flags to `rustc`, `clippy`, or other lint tools when `-Zlints` is used. + +This would work with +[RFC 2906 `workspace-deduplicate`](https://rust-lang.github.io/rfcs/2906-cargo-workspace-deduplicate.html): +```toml +[lints] +workspace = true + +[workspace.lints.rust] +unsafe = "forbid" +``` + +#### Documentation Updates + +##### The `lints` section + +*as a new ["Manifest Format" entry](./manifest.html#the-manifest-format)* + +Override the default level of lints from different tools by assigning them to a new level in a +table, for example: +```toml +[lints.rust] +unsafe = "forbid" +``` + +This is short-hand for: +```toml +[lints.rust] +unsafe = { level = "forbid", priority = 0 } +``` + +`level` corresponds to the lint levels in `rustc`: +- `forbid` +- `deny` +- `warn` +- `allow` + +`priority` is a signed integer that controls which lints or lint groups override other lint groups: +- lower (particularly negative) numbers have lower priority, being overridden + by higher numbers, and show up first on the command-line to tools like + `rustc` + +To know which table under `[lints]` a particular lint belongs under, it is the part before `::` in the lint +name. If there isn't a `::`, then the tool is `rust`. For example a warning +about `unsafe` would be `lints.rust.unsafe` but a lint about +`clippy::enum_glob_use` would be `lints.clippy.enum_glob_use`. + +For example: +```toml +[lints.rust] +unsafe = "forbid" + +[lints.clippy] +enum_glob_use = "deny" +``` + +##### The `lints` table + +*as a new [`[workspace]` entry](./workspaces.html#the-workspace-section)* + +The `workspace.lints` table is where you define lint configuration to be inherited by members of a workspace. + +Specifying a workspace lint configuration is similar to package lints. + +Example: + +```toml +# [PROJECT_DIR]/Cargo.toml +[workspace] +members = ["crates/*"] + +[workspace.lints.rust] +unsafe = "forbid" +``` + +```toml +# [PROJECT_DIR]/crates/bar/Cargo.toml +[package] +name = "bar" +version = "0.1.0" + +[lints] +workspace = true +``` + ## Stabilized and removed features ### Compile progress diff --git a/src/tools/cargo/src/etc/man/cargo-add.1 b/src/tools/cargo/src/etc/man/cargo-add.1 index 086a561fd..f69e6d0db 100644 --- a/src/tools/cargo/src/etc/man/cargo-add.1 +++ b/src/tools/cargo/src/etc/man/cargo-add.1 @@ -140,6 +140,16 @@ crates, the features for a specific crate may be enabled with \fBpackage\-name/feature\-name\fR syntax. This flag may be specified multiple times, which enables all specified features. .RE +.sp +\fB\-\-ignore\-rust\-version\fR +.RS 4 +Ignore \fBrust\-version\fR specification in packages. +.sp +This option is unstable and available only on the +\fInightly channel\fR <https://doc.rust\-lang.org/book/appendix\-07\-nightly\-rust.html> +and requires the \fB\-Z unstable\-options\fR flag to enable. +See <https://github.com/rust\-lang/cargo/issues/5579> for more information. +.RE .SS "Display Options" .sp \fB\-v\fR, diff --git a/src/tools/cargo/src/etc/man/cargo-bench.1 b/src/tools/cargo/src/etc/man/cargo-bench.1 index b95902c4e..44ff593fd 100644 --- a/src/tools/cargo/src/etc/man/cargo-bench.1 +++ b/src/tools/cargo/src/etc/man/cargo-bench.1 @@ -145,11 +145,17 @@ available) .sp The default behavior can be changed by setting the \fBbench\fR flag for the target in the manifest settings. Setting examples to \fBbench = true\fR will build and -run the example as a benchmark. Setting targets to \fBbench = false\fR will stop -them from being benchmarked by default. Target selection options that take a -target by name ignore the \fBbench\fR flag and will always benchmark the given +run the example as a benchmark, replacing the example\[cq]s \fBmain\fR function with +the libtest harness. +.sp +Setting targets to \fBbench = false\fR will stop them from being bencharmked by +default. Target selection options that take a target by name (such as +\fB\-\-example foo\fR) ignore the \fBbench\fR flag and will always benchmark the given target. .sp +See \fIConfiguring a target\fR <https://doc.rust\-lang.org/cargo/reference/cargo\-targets.html#configuring\-a\-target> +for more information on per\-target settings. +.sp Binary targets are automatically built if there is an integration test or benchmark being selected to benchmark. This allows an integration test to execute the binary to exercise and test its behavior. diff --git a/src/tools/cargo/src/etc/man/cargo-install.1 b/src/tools/cargo/src/etc/man/cargo-install.1 index d0e5c5181..a9eb6266b 100644 --- a/src/tools/cargo/src/etc/man/cargo-install.1 +++ b/src/tools/cargo/src/etc/man/cargo-install.1 @@ -263,7 +263,7 @@ is specified. .sp \fB\-\-debug\fR .RS 4 -Build with the \fBdev\fR profile instead the \fBrelease\fR profile. +Build with the \fBdev\fR profile instead of the \fBrelease\fR profile. See also the \fB\-\-profile\fR option for choosing a specific profile by name. .RE .sp diff --git a/src/tools/cargo/src/etc/man/cargo-metadata.1 b/src/tools/cargo/src/etc/man/cargo-metadata.1 index 8549290cd..f2ebb63c7 100644 --- a/src/tools/cargo/src/etc/man/cargo-metadata.1 +++ b/src/tools/cargo/src/etc/man/cargo-metadata.1 @@ -209,6 +209,12 @@ The output has the following format: "workspace_members": [ "my\-package 0.1.0 (path+file:///path/to/my\-package)", ], + /* Array of default members of the workspace. + Each entry is the Package ID for the package. + */ + "workspace_default_members": [ + "my\-package 0.1.0 (path+file:///path/to/my\-package)", + ], // The resolved dependency graph for the entire workspace. The enabled // features are based on the enabled features for the "current" package. // Inactivated optional dependencies are not listed. diff --git a/src/tools/cargo/src/etc/man/cargo-test.1 b/src/tools/cargo/src/etc/man/cargo-test.1 index 85260b067..1ee2f7672 100644 --- a/src/tools/cargo/src/etc/man/cargo-test.1 +++ b/src/tools/cargo/src/etc/man/cargo-test.1 @@ -149,13 +149,20 @@ available) .sp The default behavior can be changed by setting the \fBtest\fR flag for the target in the manifest settings. Setting examples to \fBtest = true\fR will build and run -the example as a test. Setting targets to \fBtest = false\fR will stop them from -being tested by default. Target selection options that take a target by name +the example as a test, replacing the example\[cq]s \fBmain\fR function with the +libtest harness. If you don\[cq]t want the \fBmain\fR function replaced, also include +\fBharness = false\fR, in which case the example will be built and executed as\-is. +.sp +Setting targets to \fBtest = false\fR will stop them from being tested by default. +Target selection options that take a target by name (such as \fB\-\-example foo\fR) ignore the \fBtest\fR flag and will always test the given target. .sp Doc tests for libraries may be disabled by setting \fBdoctest = false\fR for the library in the manifest. .sp +See \fIConfiguring a target\fR <https://doc.rust\-lang.org/cargo/reference/cargo\-targets.html#configuring\-a\-target> +for more information on per\-target settings. +.sp Binary targets are automatically built if there is an integration test or benchmark being selected to test. This allows an integration test to execute the binary to exercise and test its behavior. diff --git a/src/tools/cargo/src/etc/man/cargo-yank.1 b/src/tools/cargo/src/etc/man/cargo-yank.1 index 423c7bc99..107c59e49 100644 --- a/src/tools/cargo/src/etc/man/cargo-yank.1 +++ b/src/tools/cargo/src/etc/man/cargo-yank.1 @@ -14,15 +14,94 @@ The yank command removes a previously published crate\[cq]s version from the server\[cq]s index. This command does not delete any data, and the crate will still be available for download via the registry\[cq]s download link. .sp -Note that existing crates locked to a yanked version will still be able to -download the yanked version to use it. Cargo will, however, not allow any new -crates to be locked to any yanked version. +Cargo will not use a yanked version for any new project or checkout without a +pre\-existing lockfile, and will generate an error if there are no longer +any compatible versions for your crate. .sp This command requires you to be authenticated with either the \fB\-\-token\fR option or using \fBcargo\-login\fR(1). .sp If the crate name is not specified, it will use the package name from the current directory. +.SS "How yank works" +For example, the \fBfoo\fR crate published version \fB1.5.0\fR and another crate \fBbar\fR +declared a dependency on version \fBfoo = "1.5"\fR\&. Now \fBfoo\fR releases a new, but +not semver compatible, version \fB2.0.0\fR, and finds a critical issue with \fB1.5.0\fR\&. +If \fB1.5.0\fR is yanked, no new project or checkout without an existing lockfile +will be able to use crate \fBbar\fR as it relies on \fB1.5\fR\&. +.sp +In this case, the maintainers of \fBfoo\fR should first publish a semver compatible +version such as \fB1.5.1\fR prior to yanking \fB1.5.0\fR so that \fBbar\fR and all projects +that depend on \fBbar\fR will continue to work. +.sp +As another example, consider a crate \fBbar\fR with published versions \fB1.5.0\fR, +\fB1.5.1\fR, \fB1.5.2\fR, \fB2.0.0\fR and \fB3.0.0\fR\&. The following table identifies the +versions cargo could use in the absence of a lockfile for different SemVer +requirements, following a given release being yanked: + +.TS +allbox tab(:); +lt lt lt lt. +T{ +Yanked Version / SemVer requirement +T}:T{ +\fBbar = "1.5.0"\fR +T}:T{ +\fBbar = "=1.5.0"\fR +T}:T{ +\fBbar = "2.0.0"\fR +T} +T{ +\fB1.5.0\fR +T}:T{ +Use either \fB1.5.1\fR or \fB1.5.2\fR +T}:T{ +\fBReturn Error\fR +T}:T{ +Use \fB2.0.0\fR +T} +T{ +\fB1.5.1\fR +T}:T{ +Use either \fB1.5.0\fR or \fB1.5.2\fR +T}:T{ +Use \fB1.5.0\fR +T}:T{ +Use \fB2.0.0\fR +T} +T{ +\fB2.0.0\fR +T}:T{ +Use either \fB1.5.0\fR, \fB1.5.1\fR or \fB0.22.2\fR +T}:T{ +Use \fB1.5.0\fR +T}:T{ +\fBReturn Error\fR +T} +.TE +.sp +.SS "When to yank" +Crates should only be yanked in exceptional circumstances, for example, an +accidental publish, an unintentional SemVer breakages, or a significantly +broken and unusable crate. In the case of security vulnerabilities, \fIRustSec\fR <https://rustsec.org/> +is typically a less disruptive mechanism to inform users and encourage them +to upgrade, and avoids the possibility of significant downstream disruption +irrespective of susceptibility to the vulnerability in question. +.sp +A common workflow is to yank a crate having already published a semver +compatible version, to reduce the probability of preventing dependent +crates from compiling. +.sp +When addressing copyright, licensing, or personal data issues with a published +crate, simply yanking it may not suffice. In such cases, contact the maintainers +of the registry you used. For crates.io, refer to their \fIpolicies\fR <https://crates.io/policies> and contact +them at <help@crates.io>\&. +.sp +If credentials have been leaked, the recommended course of action is to revoke +them immediately. Once a crate has been published, it is impossible to determine +if the leaked credentials have been copied. Yanking the crate only prevents new +users from downloading it, but cannot stop those who have already downloaded it +from keeping or even spreading the leaked credentials. .SH "OPTIONS" .SS "Yank Options" .sp diff --git a/src/tools/cargo/tests/testsuite/alt_registry.rs b/src/tools/cargo/tests/testsuite/alt_registry.rs index 97da909b8..ac60ca92f 100644 --- a/src/tools/cargo/tests/testsuite/alt_registry.rs +++ b/src/tools/cargo/tests/testsuite/alt_registry.rs @@ -366,6 +366,7 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. "repository": null, "homepage": null, "documentation": null, + "rust_version": null, "vers": "0.0.1" }"#, "foo-0.0.1.crate", @@ -515,6 +516,7 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. "repository": null, "homepage": null, "documentation": null, + "rust_version": null, "vers": "0.0.1" }"#, "foo-0.0.1.crate", @@ -607,6 +609,7 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. "repository": null, "homepage": null, "documentation": null, + "rust_version": null, "vers": "0.0.1" }"#, "foo-0.0.1.crate", @@ -899,6 +902,9 @@ fn alt_reg_metadata() { "workspace_members": [ "foo 0.0.1 (path+file:[..]/foo)" ], + "workspace_default_members": [ + "foo 0.0.1 (path+file:[..]/foo)" + ], "resolve": null, "target_directory": "[..]/foo/target", "version": 1, @@ -1099,6 +1105,9 @@ fn alt_reg_metadata() { "workspace_members": [ "foo 0.0.1 (path+file:[..]/foo)" ], + "workspace_default_members": [ + "foo 0.0.1 (path+file:[..]/foo)" + ], "resolve": "{...}", "target_directory": "[..]/foo/target", "version": 1, @@ -1262,6 +1271,9 @@ fn unknown_registry() { "workspace_members": [ "foo 0.0.1 (path+file://[..]/foo)" ], + "workspace_default_members": [ + "foo 0.0.1 (path+file://[..]/foo)" + ], "resolve": "{...}", "target_directory": "[..]/foo/target", "version": 1, diff --git a/src/tools/cargo/tests/testsuite/artifact_dep.rs b/src/tools/cargo/tests/testsuite/artifact_dep.rs index ec6bb7103..08e413bf5 100644 --- a/src/tools/cargo/tests/testsuite/artifact_dep.rs +++ b/src/tools/cargo/tests/testsuite/artifact_dep.rs @@ -1956,6 +1956,7 @@ You may press ctrl-c [..] "readme": null, "readme_file": null, "repository": "foo", + "rust_version": null, "vers": "0.1.0" } "#, diff --git a/src/tools/cargo/tests/testsuite/bad_config.rs b/src/tools/cargo/tests/testsuite/bad_config.rs index ca51b101e..4434ea90d 100644 --- a/src/tools/cargo/tests/testsuite/bad_config.rs +++ b/src/tools/cargo/tests/testsuite/bad_config.rs @@ -780,8 +780,8 @@ fn empty_dependencies() { p.cargo("check") .with_stderr_contains( "\ -warning: dependency (bar) specified without providing a local path, Git repository, or version \ -to use. This will be considered an error in future versions +warning: dependency (bar) specified without providing a local path, Git repository, version, \ +or workspace dependency to use. This will be considered an error in future versions ", ) .run(); @@ -1317,10 +1317,42 @@ fn bad_debuginfo() { .with_status(101) .with_stderr( "\ +error: failed to parse manifest [..] + +Caused by: + invalid value: string \"a\", expected a boolean, 0, 1, 2, \"line-tables-only\", or \"line-directives-only\" + in `profile.dev.debug` +", + ) + .run(); +} + +#[cargo_test] +fn bad_debuginfo2() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.0" + authors = [] + + [profile.dev] + debug = 3.6 + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("check") + .with_status(101) + .with_stderr( + "\ error: failed to parse manifest at `[..]` Caused by: - expected a boolean or an integer + invalid type: floating point `3.6`, expected a boolean, 0, 1, 2, \"line-tables-only\", or \"line-directives-only\" in `profile.dev.debug` ", ) diff --git a/src/tools/cargo/tests/testsuite/build.rs b/src/tools/cargo/tests/testsuite/build.rs index 8a1b6ca86..7b555a71b 100644 --- a/src/tools/cargo/tests/testsuite/build.rs +++ b/src/tools/cargo/tests/testsuite/build.rs @@ -3885,7 +3885,7 @@ fn compiler_json_error_format() { }, "profile": { "debug_assertions": true, - "debuginfo": null, + "debuginfo": 0, "opt_level": "0", "overflow_checks": true, "test": false diff --git a/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/in/Cargo.toml new file mode 100644 index 000000000..cac16bb94 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/in/Cargo.toml @@ -0,0 +1,8 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" + +[dependencies] +your-face = { } diff --git a/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/in/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/in/src/lib.rs new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/in/src/lib.rs @@ -0,0 +1 @@ + diff --git a/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/mod.rs new file mode 100644 index 000000000..f6c507188 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/mod.rs @@ -0,0 +1,25 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::prelude::*; +use cargo_test_support::Project; + +use crate::cargo_add::init_registry; +use cargo_test_support::curr_dir; + +#[cargo_test] +fn case() { + init_registry(); + let project = Project::from_template(curr_dir!().join("in")); + let project_root = project.root(); + let cwd = &project_root; + + snapbox::cmd::Command::cargo_ui() + .arg("add") + .arg_line("your-face --features eyes") + .current_dir(cwd) + .assert() + .code(101) + .stdout_matches_path(curr_dir!().join("stdout.log")) + .stderr_matches_path(curr_dir!().join("stderr.log")); + + assert_ui().subset_matches(curr_dir!().join("out"), &project_root); +} diff --git a/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/out/Cargo.toml new file mode 100644 index 000000000..cac16bb94 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/out/Cargo.toml @@ -0,0 +1,8 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" + +[dependencies] +your-face = { } diff --git a/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/stderr.log b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/stderr.log new file mode 100644 index 000000000..3acd7b944 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/stderr.log @@ -0,0 +1 @@ +error: unrecognized dependency source for `your-face`, expected a local path, Git repository, version, or workspace dependency to be specified diff --git a/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/stdout.log b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/stdout.log new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/stdout.log diff --git a/src/tools/cargo/tests/testsuite/cargo_add/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/mod.rs index ca58474d2..cd7e94e09 100644 --- a/src/tools/cargo/tests/testsuite/cargo_add/mod.rs +++ b/src/tools/cargo/tests/testsuite/cargo_add/mod.rs @@ -15,6 +15,7 @@ mod dev; mod dev_build_conflict; mod dev_prefer_existing_version; mod dry_run; +mod empty_dep_table; mod features; mod features_empty; mod features_multiple_occurrences; @@ -101,6 +102,10 @@ mod quiet; mod registry; mod rename; mod require_weak; +mod rust_version_ignore; +mod rust_version_incompatible; +mod rust_version_latest; +mod rust_version_older; mod sorted_table_with_dotted_item; mod target; mod target_cfg; diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/in/Cargo.toml new file mode 100644 index 000000000..b24cd9deb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/in/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +rust-version = "1.68" diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/in/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/in/src/lib.rs new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/in/src/lib.rs diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/mod.rs new file mode 100644 index 000000000..9aa11eaac --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/mod.rs @@ -0,0 +1,36 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::prelude::*; +use cargo_test_support::Project; + +use crate::cargo_add::init_registry; +use cargo_test_support::curr_dir; + +#[cargo_test] +fn case() { + init_registry(); + + cargo_test_support::registry::Package::new("rust-version-user", "0.1.0") + .rust_version("1.66") + .publish(); + cargo_test_support::registry::Package::new("rust-version-user", "0.2.1") + .rust_version("1.72") + .publish(); + + let project = Project::from_template(curr_dir!().join("in")); + let project_root = project.root(); + let cwd = &project_root; + + snapbox::cmd::Command::cargo_ui() + .arg("-Zmsrv-policy") + .arg("add") + .arg("--ignore-rust-version") + .arg_line("rust-version-user") + .current_dir(cwd) + .masquerade_as_nightly_cargo(&["msrv-policy"]) + .assert() + .success() + .stdout_matches_path(curr_dir!().join("stdout.log")) + .stderr_matches_path(curr_dir!().join("stderr.log")); + + assert_ui().subset_matches(curr_dir!().join("out"), &project_root); +} diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/out/Cargo.toml new file mode 100644 index 000000000..62164a344 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/out/Cargo.toml @@ -0,0 +1,9 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +rust-version = "1.68" + +[dependencies] +rust-version-user = "0.2.1" diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/out/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/out/src/lib.rs new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/out/src/lib.rs diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/stderr.log b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/stderr.log new file mode 100644 index 000000000..430abe31b --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/stderr.log @@ -0,0 +1,2 @@ + Updating `dummy-registry` index + Adding rust-version-user v0.2.1 to dependencies. diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/stdout.log b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/stdout.log new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/stdout.log diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/in/Cargo.toml new file mode 100644 index 000000000..ef6fce441 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/in/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +rust-version = "1.56" diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/in/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/in/src/lib.rs new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/in/src/lib.rs diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/mod.rs new file mode 100644 index 000000000..6baad0e05 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/mod.rs @@ -0,0 +1,38 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::prelude::*; +use cargo_test_support::Project; + +use crate::cargo_add::init_registry; +use cargo_test_support::curr_dir; + +#[cargo_test] +fn case() { + init_registry(); + + cargo_test_support::registry::Package::new("rust-version-user", "0.1.0") + .rust_version("1.66") + .publish(); + cargo_test_support::registry::Package::new("rust-version-user", "0.1.1") + .rust_version("1.66") + .publish(); + cargo_test_support::registry::Package::new("rust-version-user", "0.2.1") + .rust_version("1.72") + .publish(); + + let project = Project::from_template(curr_dir!().join("in")); + let project_root = project.root(); + let cwd = &project_root; + + snapbox::cmd::Command::cargo_ui() + .arg("-Zmsrv-policy") + .arg("add") + .arg_line("rust-version-user") + .current_dir(cwd) + .masquerade_as_nightly_cargo(&["msrv-policy"]) + .assert() + .failure() + .stdout_matches_path(curr_dir!().join("stdout.log")) + .stderr_matches_path(curr_dir!().join("stderr.log")); + + assert_ui().subset_matches(curr_dir!().join("out"), &project_root); +} diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/out/Cargo.toml new file mode 100644 index 000000000..ef6fce441 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/out/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +rust-version = "1.56" diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/out/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/out/src/lib.rs new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/out/src/lib.rs diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/stderr.log b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/stderr.log new file mode 100644 index 000000000..babed5b23 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/stderr.log @@ -0,0 +1,4 @@ + Updating `dummy-registry` index +error: could not find version of crate `rust-version-user` that satisfies this package's rust-version of 1.56 +help: use `--ignore-rust-version` to override this behavior +note: the lowest rust-version available for `rust-version-user` is 1.66, used in version 0.1.1 diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/stdout.log b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/stdout.log new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/stdout.log diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/in/Cargo.toml new file mode 100644 index 000000000..d9358a5de --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/in/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +rust-version = "1.72" diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/in/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/in/src/lib.rs new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/in/src/lib.rs diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/mod.rs new file mode 100644 index 000000000..60e38960f --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/mod.rs @@ -0,0 +1,35 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::prelude::*; +use cargo_test_support::Project; + +use crate::cargo_add::init_registry; +use cargo_test_support::curr_dir; + +#[cargo_test] +fn case() { + init_registry(); + + cargo_test_support::registry::Package::new("rust-version-user", "0.1.0") + .rust_version("1.66") + .publish(); + cargo_test_support::registry::Package::new("rust-version-user", "0.2.1") + .rust_version("1.72") + .publish(); + + let project = Project::from_template(curr_dir!().join("in")); + let project_root = project.root(); + let cwd = &project_root; + + snapbox::cmd::Command::cargo_ui() + .arg("-Zmsrv-policy") + .arg("add") + .arg_line("rust-version-user") + .current_dir(cwd) + .masquerade_as_nightly_cargo(&["msrv-policy"]) + .assert() + .success() + .stdout_matches_path(curr_dir!().join("stdout.log")) + .stderr_matches_path(curr_dir!().join("stderr.log")); + + assert_ui().subset_matches(curr_dir!().join("out"), &project_root); +} diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/out/Cargo.toml new file mode 100644 index 000000000..f824b41c3 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/out/Cargo.toml @@ -0,0 +1,9 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +rust-version = "1.72" + +[dependencies] +rust-version-user = "0.2.1" diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/out/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/out/src/lib.rs new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/out/src/lib.rs diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/stderr.log b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/stderr.log new file mode 100644 index 000000000..430abe31b --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/stderr.log @@ -0,0 +1,2 @@ + Updating `dummy-registry` index + Adding rust-version-user v0.2.1 to dependencies. diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/stdout.log b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/stdout.log new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/stdout.log diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/in/Cargo.toml new file mode 100644 index 000000000..6fd6f1232 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/in/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +rust-version = "1.70" diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/in/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/in/src/lib.rs new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/in/src/lib.rs diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/mod.rs new file mode 100644 index 000000000..60e38960f --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/mod.rs @@ -0,0 +1,35 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::prelude::*; +use cargo_test_support::Project; + +use crate::cargo_add::init_registry; +use cargo_test_support::curr_dir; + +#[cargo_test] +fn case() { + init_registry(); + + cargo_test_support::registry::Package::new("rust-version-user", "0.1.0") + .rust_version("1.66") + .publish(); + cargo_test_support::registry::Package::new("rust-version-user", "0.2.1") + .rust_version("1.72") + .publish(); + + let project = Project::from_template(curr_dir!().join("in")); + let project_root = project.root(); + let cwd = &project_root; + + snapbox::cmd::Command::cargo_ui() + .arg("-Zmsrv-policy") + .arg("add") + .arg_line("rust-version-user") + .current_dir(cwd) + .masquerade_as_nightly_cargo(&["msrv-policy"]) + .assert() + .success() + .stdout_matches_path(curr_dir!().join("stdout.log")) + .stderr_matches_path(curr_dir!().join("stderr.log")); + + assert_ui().subset_matches(curr_dir!().join("out"), &project_root); +} diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/out/Cargo.toml new file mode 100644 index 000000000..14737e328 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/out/Cargo.toml @@ -0,0 +1,9 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +rust-version = "1.70" + +[dependencies] +rust-version-user = "0.1.0" diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/out/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/out/src/lib.rs new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/out/src/lib.rs diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/stderr.log b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/stderr.log new file mode 100644 index 000000000..4c5988d0b --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/stderr.log @@ -0,0 +1,3 @@ + Updating `dummy-registry` index +warning: ignoring `rust-version-user@0.2.1` (which has a rust-version of 1.72) to satisfy this package's rust-version of 1.70 (use `--ignore-rust-version` to override) + Adding rust-version-user v0.1.0 to dependencies. diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/stdout.log b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/stdout.log new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/stdout.log diff --git a/src/tools/cargo/tests/testsuite/cargo_env_config.rs b/src/tools/cargo/tests/testsuite/cargo_env_config.rs index d80c38d0e..dbb89664d 100644 --- a/src/tools/cargo/tests/testsuite/cargo_env_config.rs +++ b/src/tools/cargo/tests/testsuite/cargo_env_config.rs @@ -1,5 +1,6 @@ //! Tests for `[env]` config. +use cargo_test_support::basic_manifest; use cargo_test_support::{basic_bin_manifest, project}; #[cargo_test] @@ -58,29 +59,31 @@ fn env_invalid() { } #[cargo_test] -fn env_no_cargo_home() { +fn env_no_disallowed() { + // Checks for keys that are not allowed in the [env] table. let p = project() - .file("Cargo.toml", &basic_bin_manifest("foo")) - .file( - "src/main.rs", - r#" - fn main() { - } - "#, - ) - .file( - ".cargo/config", - r#" - [env] - CARGO_HOME = "/" - "#, - ) + .file("Cargo.toml", &basic_manifest("foo", "1.0.0")) + .file("src/lib.rs", "") .build(); - p.cargo("check") - .with_status(101) - .with_stderr_contains("[..]setting the `CARGO_HOME` environment variable is not supported in the `[env]` configuration table") - .run(); + for disallowed in &["CARGO_HOME", "RUSTUP_HOME", "RUSTUP_TOOLCHAIN"] { + p.change_file( + ".cargo/config", + &format!( + r#" + [env] + {disallowed} = "foo" + "# + ), + ); + p.cargo("check") + .with_status(101) + .with_stderr(&format!( + "[ERROR] setting the `{disallowed}` environment variable \ + is not supported in the `[env]` configuration table" + )) + .run(); + } } #[cargo_test] @@ -179,3 +182,60 @@ fn env_no_override() { .with_stdout_contains("CARGO_PKG_NAME:unchanged") .run(); } + +#[cargo_test] +fn env_applied_to_target_info_discovery_rustc() { + let wrapper = project() + .at("wrapper") + .file("Cargo.toml", &basic_manifest("wrapper", "1.0.0")) + .file( + "src/main.rs", + r#" + fn main() { + let mut args = std::env::args().skip(1); + let env_test = std::env::var("ENV_TEST").unwrap(); + eprintln!("WRAPPER ENV_TEST:{env_test}"); + let status = std::process::Command::new(&args.next().unwrap()) + .args(args).status().unwrap(); + std::process::exit(status.code().unwrap_or(1)); + } + "#, + ) + .build(); + wrapper.cargo("build").run(); + let wrapper = &wrapper.bin("wrapper"); + + let p = project() + .file("Cargo.toml", &basic_bin_manifest("foo")) + .file( + "src/main.rs", + r#" + fn main() { + eprintln!( "MAIN ENV_TEST:{}", std::env!("ENV_TEST") ); + } + "#, + ) + .file( + ".cargo/config", + r#" + [env] + ENV_TEST = "from-config" + "#, + ) + .build(); + + p.cargo("run") + .env("RUSTC_WORKSPACE_WRAPPER", wrapper) + .with_stderr_contains("WRAPPER ENV_TEST:from-config") + .with_stderr_contains("MAIN ENV_TEST:from-config") + .run(); + + // Ensure wrapper also maintains the same overridden priority for envs. + p.cargo("clean").run(); + p.cargo("run") + .env("ENV_TEST", "from-env") + .env("RUSTC_WORKSPACE_WRAPPER", wrapper) + .with_stderr_contains("WRAPPER ENV_TEST:from-env") + .with_stderr_contains("MAIN ENV_TEST:from-env") + .run(); +} diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table.in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table.in/Cargo.toml new file mode 100644 index 000000000..b7a2e9036 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table.in/Cargo.toml @@ -0,0 +1,21 @@ +[workspace] +members = [ + "crates/*", +] + +[workspace.package] +authors = ["Rustaceans"] +description = "foo" +edition = "2018" +homepage = "foo" +keywords = ["foo", "bar"] +readme = "README.md" +rust-version = "1.67.0" +categories = ["algorithms"] +documentation = "foo" +exclude = ["foo"] +include = ["foo"] +license = "MIT OR Apache-2.0" +publish = false +repository = "foo" +version = "1.2.3" diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table.in/README.md b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table.in/README.md new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table.in/README.md diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table.in/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table.in/src/lib.rs new file mode 100644 index 000000000..7d12d9af8 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table.in/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/in b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/in new file mode 120000 index 000000000..aba551efe --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/in @@ -0,0 +1 @@ +../inherit_workspace_package_table.in
\ No newline at end of file diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/mod.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/mod.rs new file mode 100644 index 000000000..9b9642468 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/mod.rs @@ -0,0 +1,22 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::curr_dir; +use cargo_test_support::CargoCommand; +use cargo_test_support::Project; + +#[cargo_test] +fn case() { + let project = Project::from_template(curr_dir!().join("in")); + let project_root = project.root(); + let cwd = &project_root; + + snapbox::cmd::Command::cargo_ui() + .arg("new") + .args(["crates/foo"]) + .current_dir(cwd) + .assert() + .success() + .stdout_matches_path(curr_dir!().join("stdout.log")) + .stderr_matches_path(curr_dir!().join("stderr.log")); + + assert_ui().subset_matches(curr_dir!().join("out"), &project_root); +} diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/out/Cargo.toml new file mode 100644 index 000000000..b7a2e9036 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/out/Cargo.toml @@ -0,0 +1,21 @@ +[workspace] +members = [ + "crates/*", +] + +[workspace.package] +authors = ["Rustaceans"] +description = "foo" +edition = "2018" +homepage = "foo" +keywords = ["foo", "bar"] +readme = "README.md" +rust-version = "1.67.0" +categories = ["algorithms"] +documentation = "foo" +exclude = ["foo"] +include = ["foo"] +license = "MIT OR Apache-2.0" +publish = false +repository = "foo" +version = "1.2.3" diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/out/crates/foo/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/out/crates/foo/Cargo.toml new file mode 100644 index 000000000..137ed1c87 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/out/crates/foo/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "foo" +authors.workspace = true +description.workspace = true +edition.workspace = true +homepage.workspace = true +keywords.workspace = true +readme.workspace = true +rust-version.workspace = true +categories.workspace = true +documentation.workspace = true +exclude.workspace = true +include.workspace = true +license.workspace = true +publish.workspace = true +repository.workspace = true +version.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/out/crates/foo/src/main.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/out/crates/foo/src/main.rs new file mode 100644 index 000000000..e7a11a969 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/out/crates/foo/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/out/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/out/src/lib.rs new file mode 100644 index 000000000..7d12d9af8 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/out/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/stderr.log b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/stderr.log new file mode 100644 index 000000000..90150cdf5 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/stderr.log @@ -0,0 +1 @@ + Created binary (application) `crates/foo` package diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/stdout.log b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/stdout.log new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/stdout.log diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/in b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/in new file mode 120000 index 000000000..aba551efe --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/in @@ -0,0 +1 @@ +../inherit_workspace_package_table.in
\ No newline at end of file diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/mod.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/mod.rs new file mode 100644 index 000000000..c3ac2d375 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/mod.rs @@ -0,0 +1,22 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::curr_dir; +use cargo_test_support::CargoCommand; +use cargo_test_support::Project; + +#[cargo_test] +fn case() { + let project = Project::from_template(curr_dir!().join("in")); + let project_root = project.root(); + let cwd = &project_root; + + snapbox::cmd::Command::cargo_ui() + .arg("new") + .args(["crates/foo", "--edition", "2021"]) + .current_dir(cwd) + .assert() + .success() + .stdout_matches_path(curr_dir!().join("stdout.log")) + .stderr_matches_path(curr_dir!().join("stderr.log")); + + assert_ui().subset_matches(curr_dir!().join("out"), &project_root); +} diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/out/Cargo.toml new file mode 100644 index 000000000..b7a2e9036 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/out/Cargo.toml @@ -0,0 +1,21 @@ +[workspace] +members = [ + "crates/*", +] + +[workspace.package] +authors = ["Rustaceans"] +description = "foo" +edition = "2018" +homepage = "foo" +keywords = ["foo", "bar"] +readme = "README.md" +rust-version = "1.67.0" +categories = ["algorithms"] +documentation = "foo" +exclude = ["foo"] +include = ["foo"] +license = "MIT OR Apache-2.0" +publish = false +repository = "foo" +version = "1.2.3" diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/out/crates/foo/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/out/crates/foo/Cargo.toml new file mode 100644 index 000000000..abb427d43 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/out/crates/foo/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "foo" +edition = "2021" +authors.workspace = true +description.workspace = true +homepage.workspace = true +keywords.workspace = true +readme.workspace = true +rust-version.workspace = true +categories.workspace = true +documentation.workspace = true +exclude.workspace = true +include.workspace = true +license.workspace = true +publish.workspace = true +repository.workspace = true +version.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/out/crates/foo/src/main.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/out/crates/foo/src/main.rs new file mode 100644 index 000000000..e7a11a969 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/out/crates/foo/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/out/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/out/src/lib.rs new file mode 100644 index 000000000..7d12d9af8 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/out/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/stderr.log b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/stderr.log new file mode 100644 index 000000000..90150cdf5 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/stderr.log @@ -0,0 +1 @@ + Created binary (application) `crates/foo` package diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/stdout.log b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/stdout.log new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/stdout.log diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/in b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/in new file mode 120000 index 000000000..aba551efe --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/in @@ -0,0 +1 @@ +../inherit_workspace_package_table.in
\ No newline at end of file diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/mod.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/mod.rs new file mode 100644 index 000000000..16ec66ea2 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/mod.rs @@ -0,0 +1,22 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::curr_dir; +use cargo_test_support::CargoCommand; +use cargo_test_support::Project; + +#[cargo_test] +fn case() { + let project = Project::from_template(curr_dir!().join("in")); + let project_root = project.root(); + let cwd = &project_root; + + snapbox::cmd::Command::cargo_ui() + .arg("new") + .args(["crates/foo", "--registry", "foo"]) + .current_dir(cwd) + .assert() + .success() + .stdout_matches_path(curr_dir!().join("stdout.log")) + .stderr_matches_path(curr_dir!().join("stderr.log")); + + assert_ui().subset_matches(curr_dir!().join("out"), &project_root); +} diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/out/Cargo.toml new file mode 100644 index 000000000..b7a2e9036 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/out/Cargo.toml @@ -0,0 +1,21 @@ +[workspace] +members = [ + "crates/*", +] + +[workspace.package] +authors = ["Rustaceans"] +description = "foo" +edition = "2018" +homepage = "foo" +keywords = ["foo", "bar"] +readme = "README.md" +rust-version = "1.67.0" +categories = ["algorithms"] +documentation = "foo" +exclude = ["foo"] +include = ["foo"] +license = "MIT OR Apache-2.0" +publish = false +repository = "foo" +version = "1.2.3" diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/out/crates/foo/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/out/crates/foo/Cargo.toml new file mode 100644 index 000000000..642a64e46 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/out/crates/foo/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "foo" +publish = ["foo"] +authors.workspace = true +description.workspace = true +edition.workspace = true +homepage.workspace = true +keywords.workspace = true +readme.workspace = true +rust-version.workspace = true +categories.workspace = true +documentation.workspace = true +exclude.workspace = true +include.workspace = true +license.workspace = true +repository.workspace = true +version.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/out/crates/foo/src/main.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/out/crates/foo/src/main.rs new file mode 100644 index 000000000..e7a11a969 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/out/crates/foo/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/out/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/out/src/lib.rs new file mode 100644 index 000000000..7d12d9af8 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/out/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/stderr.log b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/stderr.log new file mode 100644 index 000000000..90150cdf5 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/stderr.log @@ -0,0 +1 @@ + Created binary (application) `crates/foo` package diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/stdout.log b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/stdout.log new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/stdout.log diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/in/Cargo.toml new file mode 100644 index 000000000..112fef55c --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/in/Cargo.toml @@ -0,0 +1,20 @@ +[workspace] +members = [ + "crates/*", +] + +[workspace.package] +authors = ["Rustaceans"] +description = "foo" +edition = "2018" +homepage = "foo" +keywords = ["foo", "bar"] +readme = "README.md" +rust-version = "1.67.0" +categories = ["algorithms"] +documentation = "foo" +exclude = ["foo"] +include = ["foo"] +license = "MIT OR Apache-2.0" +publish = false +repository = "foo" diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/in/README.md b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/in/README.md new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/in/README.md diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/in/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/in/src/lib.rs new file mode 100644 index 000000000..7d12d9af8 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/in/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/mod.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/mod.rs new file mode 100644 index 000000000..9b9642468 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/mod.rs @@ -0,0 +1,22 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::curr_dir; +use cargo_test_support::CargoCommand; +use cargo_test_support::Project; + +#[cargo_test] +fn case() { + let project = Project::from_template(curr_dir!().join("in")); + let project_root = project.root(); + let cwd = &project_root; + + snapbox::cmd::Command::cargo_ui() + .arg("new") + .args(["crates/foo"]) + .current_dir(cwd) + .assert() + .success() + .stdout_matches_path(curr_dir!().join("stdout.log")) + .stderr_matches_path(curr_dir!().join("stderr.log")); + + assert_ui().subset_matches(curr_dir!().join("out"), &project_root); +} diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/out/Cargo.toml new file mode 100644 index 000000000..112fef55c --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/out/Cargo.toml @@ -0,0 +1,20 @@ +[workspace] +members = [ + "crates/*", +] + +[workspace.package] +authors = ["Rustaceans"] +description = "foo" +edition = "2018" +homepage = "foo" +keywords = ["foo", "bar"] +readme = "README.md" +rust-version = "1.67.0" +categories = ["algorithms"] +documentation = "foo" +exclude = ["foo"] +include = ["foo"] +license = "MIT OR Apache-2.0" +publish = false +repository = "foo" diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/out/crates/foo/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/out/crates/foo/Cargo.toml new file mode 100644 index 000000000..4fcf77121 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/out/crates/foo/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "foo" +version = "0.1.0" +authors.workspace = true +description.workspace = true +edition.workspace = true +homepage.workspace = true +keywords.workspace = true +readme.workspace = true +rust-version.workspace = true +categories.workspace = true +documentation.workspace = true +exclude.workspace = true +include.workspace = true +license.workspace = true +publish.workspace = true +repository.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/out/crates/foo/src/main.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/out/crates/foo/src/main.rs new file mode 100644 index 000000000..e7a11a969 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/out/crates/foo/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/out/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/out/src/lib.rs new file mode 100644 index 000000000..7d12d9af8 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/out/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/stderr.log b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/stderr.log new file mode 100644 index 000000000..90150cdf5 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/stderr.log @@ -0,0 +1 @@ + Created binary (application) `crates/foo` package diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/stdout.log b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/stdout.log new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/stdout.log diff --git a/src/tools/cargo/tests/testsuite/cargo_new/mod.rs b/src/tools/cargo/tests/testsuite/cargo_new/mod.rs new file mode 100644 index 000000000..762a70b34 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/mod.rs @@ -0,0 +1,5 @@ +mod inherit_workspace_package_table; +mod inherit_workspace_package_table_with_edition; +mod inherit_workspace_package_table_with_registry; +mod inherit_workspace_package_table_without_version; +mod not_inherit_workspace_package_table_if_not_memebers; diff --git a/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/in/Cargo.toml new file mode 100644 index 000000000..2d204581c --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/in/Cargo.toml @@ -0,0 +1,15 @@ +[workspace.package] +authors = ["Rustaceans"] +description = "foo" +edition = "2018" +homepage = "foo" +keywords = ["foo", "bar"] +readme = "README.md" +rust-version = "1.67.0" +categories = ["algorithms"] +documentation = "foo" +exclude = ["foo"] +include = ["foo"] +license = "MIT OR Apache-2.0" +publish = false +repository = "foo" diff --git a/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/in/README.md b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/in/README.md new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/in/README.md diff --git a/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/in/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/in/src/lib.rs new file mode 100644 index 000000000..7d12d9af8 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/in/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/mod.rs b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/mod.rs new file mode 100644 index 000000000..cdddf0e64 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/mod.rs @@ -0,0 +1,22 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::curr_dir; +use cargo_test_support::CargoCommand; +use cargo_test_support::Project; + +#[cargo_test] +fn case() { + let project = Project::from_template(curr_dir!().join("in")); + let project_root = project.root(); + let cwd = &project_root; + + snapbox::cmd::Command::cargo_ui() + .arg("new") + .args(["foo"]) + .current_dir(cwd) + .assert() + .success() + .stdout_matches_path(curr_dir!().join("stdout.log")) + .stderr_matches_path(curr_dir!().join("stderr.log")); + + assert_ui().subset_matches(curr_dir!().join("out"), &project_root); +} diff --git a/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/out/Cargo.toml new file mode 100644 index 000000000..2d204581c --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/out/Cargo.toml @@ -0,0 +1,15 @@ +[workspace.package] +authors = ["Rustaceans"] +description = "foo" +edition = "2018" +homepage = "foo" +keywords = ["foo", "bar"] +readme = "README.md" +rust-version = "1.67.0" +categories = ["algorithms"] +documentation = "foo" +exclude = ["foo"] +include = ["foo"] +license = "MIT OR Apache-2.0" +publish = false +repository = "foo" diff --git a/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/out/foo/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/out/foo/Cargo.toml new file mode 100644 index 000000000..4fcf77121 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/out/foo/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "foo" +version = "0.1.0" +authors.workspace = true +description.workspace = true +edition.workspace = true +homepage.workspace = true +keywords.workspace = true +readme.workspace = true +rust-version.workspace = true +categories.workspace = true +documentation.workspace = true +exclude.workspace = true +include.workspace = true +license.workspace = true +publish.workspace = true +repository.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/out/foo/src/main.rs b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/out/foo/src/main.rs new file mode 100644 index 000000000..e7a11a969 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/out/foo/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/out/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/out/src/lib.rs new file mode 100644 index 000000000..7d12d9af8 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/out/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/stderr.log b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/stderr.log new file mode 100644 index 000000000..03b1ff6db --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/stderr.log @@ -0,0 +1,9 @@ +warning: compiling this new package may not work due to invalid workspace configuration + +current package believes it's in a workspace when it's not: +current: [ROOT]/case/foo/Cargo.toml +workspace: [ROOT]/case/Cargo.toml + +this may be fixable by adding `foo` to the `workspace.members` array of the manifest located at: [ROOT]/case/Cargo.toml +Alternatively, to keep it out of the workspace, add the package to the `workspace.exclude` array, or add an empty `[workspace]` table to the package's manifest. + Created binary (application) `foo` package diff --git a/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/stdout.log b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/stdout.log new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/stdout.log diff --git a/src/tools/cargo/tests/testsuite/check.rs b/src/tools/cargo/tests/testsuite/check.rs index bbcf750fb..7bc9a38a3 100644 --- a/src/tools/cargo/tests/testsuite/check.rs +++ b/src/tools/cargo/tests/testsuite/check.rs @@ -6,8 +6,8 @@ use crate::messages::raw_rustc_output; use cargo_test_support::install::exe; use cargo_test_support::paths::CargoPathExt; use cargo_test_support::registry::Package; -use cargo_test_support::tools; use cargo_test_support::{basic_bin_manifest, basic_manifest, git, project}; +use cargo_test_support::{tools, wrapped_clippy_driver}; #[cargo_test] fn check_success() { @@ -1416,25 +1416,6 @@ fn check_fixable_mixed() { #[cargo_test] fn check_fixable_warning_for_clippy() { - // A wrapper around `rustc` instead of calling `clippy` - let clippy_driver = project() - .at(cargo_test_support::paths::global_root().join("clippy-driver")) - .file("Cargo.toml", &basic_manifest("clippy-driver", "0.0.1")) - .file( - "src/main.rs", - r#" - fn main() { - let mut args = std::env::args_os(); - let _me = args.next().unwrap(); - let rustc = args.next().unwrap(); - let status = std::process::Command::new(rustc).args(args).status().unwrap(); - std::process::exit(status.code().unwrap_or(1)); - } - "#, - ) - .build(); - clippy_driver.cargo("build").run(); - let foo = project() .file( "Cargo.toml", @@ -1452,10 +1433,7 @@ fn check_fixable_warning_for_clippy() { foo.cargo("check") // We can't use `clippy` so we use a `rustc` workspace wrapper instead - .env( - "RUSTC_WORKSPACE_WRAPPER", - clippy_driver.bin("clippy-driver"), - ) + .env("RUSTC_WORKSPACE_WRAPPER", wrapped_clippy_driver()) .with_stderr_contains("[..] (run `cargo clippy --fix --lib -p foo` to apply 1 suggestion)") .run(); } diff --git a/src/tools/cargo/tests/testsuite/config.rs b/src/tools/cargo/tests/testsuite/config.rs index 92e1f4264..b0f9d167b 100644 --- a/src/tools/cargo/tests/testsuite/config.rs +++ b/src/tools/cargo/tests/testsuite/config.rs @@ -3,7 +3,7 @@ use cargo::core::{PackageIdSpec, Shell}; use cargo::util::config::{self, Config, Definition, SslVersionConfig, StringList}; use cargo::util::interning::InternedString; -use cargo::util::toml::{self as cargo_toml, VecStringOrBool as VSOB}; +use cargo::util::toml::{self as cargo_toml, TomlDebugInfo, VecStringOrBool as VSOB}; use cargo::CargoResult; use cargo_test_support::compare; use cargo_test_support::{panic_error, paths, project, symlink_supported, t}; @@ -401,7 +401,7 @@ lto = false opt_level: Some(cargo_toml::TomlOptLevel("s".to_string())), lto: Some(cargo_toml::StringOrBool::Bool(true)), codegen_units: Some(5), - debug: Some(cargo_toml::U32OrBool::Bool(true)), + debug: Some(cargo_toml::TomlDebugInfo::Full), debug_assertions: Some(true), rpath: Some(true), panic: Some("abort".to_string()), @@ -444,7 +444,7 @@ fn profile_env_var_prefix() { .build(); let p: cargo_toml::TomlProfile = config.get("profile.dev").unwrap(); assert_eq!(p.debug_assertions, None); - assert_eq!(p.debug, Some(cargo_toml::U32OrBool::U32(1))); + assert_eq!(p.debug, Some(cargo_toml::TomlDebugInfo::Limited)); let config = ConfigBuilder::new() .env("CARGO_PROFILE_DEV_DEBUG_ASSERTIONS", "false") @@ -452,7 +452,7 @@ fn profile_env_var_prefix() { .build(); let p: cargo_toml::TomlProfile = config.get("profile.dev").unwrap(); assert_eq!(p.debug_assertions, Some(false)); - assert_eq!(p.debug, Some(cargo_toml::U32OrBool::U32(1))); + assert_eq!(p.debug, Some(cargo_toml::TomlDebugInfo::Limited)); } #[cargo_test] @@ -1511,7 +1511,7 @@ fn all_profile_options() { lto: Some(cargo_toml::StringOrBool::String("thin".to_string())), codegen_backend: Some(InternedString::new("example")), codegen_units: Some(123), - debug: Some(cargo_toml::U32OrBool::U32(1)), + debug: Some(cargo_toml::TomlDebugInfo::Limited), split_debuginfo: Some("packed".to_string()), debug_assertions: Some(true), rpath: Some(true), @@ -1594,3 +1594,60 @@ known-hosts = [ Definition::Environment("CARGO_NET_SSH_KNOWN_HOSTS".to_string()) ); } + +#[cargo_test] +fn debuginfo_parsing() { + let config = ConfigBuilder::new().build(); + let p: cargo_toml::TomlProfile = config.get("profile.dev").unwrap(); + assert_eq!(p.debug, None); + + let env_test_cases = [ + (TomlDebugInfo::None, ["false", "0", "none"].as_slice()), + (TomlDebugInfo::LineDirectivesOnly, &["line-directives-only"]), + (TomlDebugInfo::LineTablesOnly, &["line-tables-only"]), + (TomlDebugInfo::Limited, &["1", "limited"]), + (TomlDebugInfo::Full, &["true", "2", "full"]), + ]; + for (expected, config_strs) in env_test_cases { + for &val in config_strs { + let config = ConfigBuilder::new() + .env("CARGO_PROFILE_DEV_DEBUG", val) + .build(); + let debug: TomlDebugInfo = config.get("profile.dev.debug").unwrap(); + assert_eq!(debug, expected, "failed to parse {val}"); + } + } + + let toml_test_cases = [ + (TomlDebugInfo::None, ["false", "0", "\"none\""].as_slice()), + ( + TomlDebugInfo::LineDirectivesOnly, + &["\"line-directives-only\""], + ), + (TomlDebugInfo::LineTablesOnly, &["\"line-tables-only\""]), + (TomlDebugInfo::Limited, &["1", "\"limited\""]), + (TomlDebugInfo::Full, &["true", "2", "\"full\""]), + ]; + for (expected, config_strs) in toml_test_cases { + for &val in config_strs { + let config = ConfigBuilder::new() + .config_arg(format!("profile.dev.debug={val}")) + .build(); + let debug: TomlDebugInfo = config.get("profile.dev.debug").unwrap(); + assert_eq!(debug, expected, "failed to parse {val}"); + } + } + + let toml_err_cases = ["\"\"", "\"unrecognized\"", "3"]; + for err_val in toml_err_cases { + let config = ConfigBuilder::new() + .config_arg(format!("profile.dev.debug={err_val}")) + .build(); + let err = config + .get::<TomlDebugInfo>("profile.dev.debug") + .unwrap_err(); + assert!(err + .to_string() + .ends_with("could not load config key `profile.dev.debug`")); + } +} diff --git a/src/tools/cargo/tests/testsuite/features_namespaced.rs b/src/tools/cargo/tests/testsuite/features_namespaced.rs index 8ec2fc2e3..f24186c15 100644 --- a/src/tools/cargo/tests/testsuite/features_namespaced.rs +++ b/src/tools/cargo/tests/testsuite/features_namespaced.rs @@ -609,6 +609,7 @@ fn json_exposed() { } ], "workspace_members": "{...}", + "workspace_default_members": "{...}", "resolve": null, "target_directory": "[..]foo/target", "version": 1, @@ -942,6 +943,7 @@ You may press ctrl-c [..] "readme": null, "readme_file": null, "repository": null, + "rust_version": null, "vers": "0.1.0" } "#, @@ -1057,6 +1059,7 @@ You may press ctrl-c [..] "readme": null, "readme_file": null, "repository": null, + "rust_version": null, "vers": "0.1.0" } "#, @@ -1213,3 +1216,81 @@ Caused by: ) .run(); } + +#[cargo_test] +fn dep_feature_when_hidden() { + // Checks for behavior with dep:bar and bar/feat syntax when there is no + // `bar` feature. + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = { path = "bar", optional = true } + + [features] + f1 = ["dep:bar"] + f2 = ["bar/bar_feat"] + "#, + ) + .file("src/lib.rs", "") + .file( + "bar/Cargo.toml", + r#" + [package] + name = "bar" + version = "0.1.0" + + [features] + bar_feat = [] + "#, + ) + .file("bar/src/lib.rs", "") + .build(); + + p.cargo("tree -f") + .arg("{p} features={f}") + .with_stdout( + "\ +foo v0.1.0 ([ROOT]/foo) features=", + ) + .with_stderr("") + .run(); + + p.cargo("tree -F f1 -f") + .arg("{p} features={f}") + .with_stdout( + "\ +foo v0.1.0 ([ROOT]/foo) features=f1 +└── bar v0.1.0 ([ROOT]/foo/bar) features= +", + ) + .with_stderr("") + .run(); + + p.cargo("tree -F f2 -f") + .arg("{p} features={f}") + .with_stdout( + "\ +foo v0.1.0 ([ROOT]/foo) features=f2 +└── bar v0.1.0 ([ROOT]/foo/bar) features=bar_feat +", + ) + .with_stderr("") + .run(); + + p.cargo("tree --all-features -f") + .arg("{p} features={f}") + .with_stdout( + "\ +foo v0.1.0 ([ROOT]/foo) features=f1,f2 +└── bar v0.1.0 ([ROOT]/foo/bar) features=bar_feat +", + ) + .with_stderr("") + .run(); +} diff --git a/src/tools/cargo/tests/testsuite/fix.rs b/src/tools/cargo/tests/testsuite/fix.rs index 54a021c03..33de721cd 100644 --- a/src/tools/cargo/tests/testsuite/fix.rs +++ b/src/tools/cargo/tests/testsuite/fix.rs @@ -5,8 +5,8 @@ use cargo_test_support::compare::assert_match_exact; use cargo_test_support::git::{self, init}; use cargo_test_support::paths::{self, CargoPathExt}; use cargo_test_support::registry::{Dependency, Package}; -use cargo_test_support::tools; -use cargo_test_support::{basic_manifest, is_nightly, project}; +use cargo_test_support::{basic_manifest, is_nightly, project, Project}; +use cargo_test_support::{tools, wrapped_clippy_driver}; #[cargo_test] fn do_not_fix_broken_builds() { @@ -53,8 +53,7 @@ fn fix_broken_if_requested() { .run(); } -#[cargo_test] -fn broken_fixes_backed_out() { +fn rustc_shim_for_cargo_fix() -> Project { // This works as follows: // - Create a `rustc` shim (the "foo" project) which will pretend that the // verification step fails. @@ -109,7 +108,6 @@ fn broken_fixes_backed_out() { fs::File::create(&first).unwrap(); } } - let status = Command::new("rustc") .args(env::args().skip(1)) .status() @@ -142,11 +140,60 @@ fn broken_fixes_backed_out() { // Build our rustc shim p.cargo("build").cwd("foo").run(); - // Attempt to fix code, but our shim will always fail the second compile + p +} + +#[cargo_test] +fn broken_fixes_backed_out() { + let p = rustc_shim_for_cargo_fix(); + // Attempt to fix code, but our shim will always fail the second compile. + p.cargo("fix --allow-no-vcs --lib") + .cwd("bar") + .env("__CARGO_FIX_YOLO", "1") + .env("RUSTC", p.root().join("foo/target/debug/foo")) + .with_stderr_contains( + "warning: failed to automatically apply fixes suggested by rustc \ + to crate `bar`\n\ + \n\ + after fixes were automatically applied the compiler reported \ + errors within these files:\n\ + \n \ + * src/lib.rs\n\ + \n\ + This likely indicates a bug in either rustc or cargo itself,\n\ + and we would appreciate a bug report! You're likely to see \n\ + a number of compiler warnings after this message which cargo\n\ + attempted to fix but failed. If you could open an issue at\n\ + https://github.com/rust-lang/rust/issues\n\ + quoting the full output of this command we'd be very appreciative!\n\ + Note that you may be able to make some more progress in the near-term\n\ + fixing code with the `--broken-code` flag\n\ + \n\ + The following errors were reported:\n\ + error: expected one of `!` or `::`, found `rust`\n\ + ", + ) + .with_stderr_contains("Original diagnostics will follow.") + .with_stderr_contains("[WARNING] variable does not need to be mutable") + .with_stderr_does_not_contain("[..][FIXED][..]") + .run(); + + // Make sure the fix which should have been applied was backed out + assert!(p.read_file("bar/src/lib.rs").contains("let mut x = 3;")); +} + +#[cargo_test] +fn broken_clippy_fixes_backed_out() { + let p = rustc_shim_for_cargo_fix(); + // Attempt to fix code, but our shim will always fail the second compile. + // Also, we use `clippy` as a workspace wrapper to make sure that we properly + // generate the report bug text. p.cargo("fix --allow-no-vcs --lib") .cwd("bar") .env("__CARGO_FIX_YOLO", "1") .env("RUSTC", p.root().join("foo/target/debug/foo")) + // We can't use `clippy` so we use a `rustc` workspace wrapper instead + .env("RUSTC_WORKSPACE_WRAPPER", wrapped_clippy_driver()) .with_stderr_contains( "warning: failed to automatically apply fixes suggested by rustc \ to crate `bar`\n\ @@ -160,7 +207,7 @@ fn broken_fixes_backed_out() { and we would appreciate a bug report! You're likely to see \n\ a number of compiler warnings after this message which cargo\n\ attempted to fix but failed. If you could open an issue at\n\ - [..]\n\ + https://github.com/rust-lang/rust-clippy/issues\n\ quoting the full output of this command we'd be very appreciative!\n\ Note that you may be able to make some more progress in the near-term\n\ fixing code with the `--broken-code` flag\n\ diff --git a/src/tools/cargo/tests/testsuite/git.rs b/src/tools/cargo/tests/testsuite/git.rs index b170c204f..7c717e967 100644 --- a/src/tools/cargo/tests/testsuite/git.rs +++ b/src/tools/cargo/tests/testsuite/git.rs @@ -548,90 +548,6 @@ Caused by: } #[cargo_test] -fn two_revs_same_deps() { - let bar = git::new("meta-dep", |project| { - project - .file("Cargo.toml", &basic_manifest("bar", "0.0.0")) - .file("src/lib.rs", "pub fn bar() -> i32 { 1 }") - }); - - let repo = git2::Repository::open(&bar.root()).unwrap(); - let rev1 = repo.revparse_single("HEAD").unwrap().id(); - - // Commit the changes and make sure we trigger a recompile - bar.change_file("src/lib.rs", "pub fn bar() -> i32 { 2 }"); - git::add(&repo); - let rev2 = git::commit(&repo); - - let foo = project() - .file( - "Cargo.toml", - &format!( - r#" - [package] - name = "foo" - version = "0.0.0" - authors = [] - - [dependencies.bar] - git = '{}' - rev = "{}" - - [dependencies.baz] - path = "../baz" - "#, - bar.url(), - rev1 - ), - ) - .file( - "src/main.rs", - r#" - extern crate bar; - extern crate baz; - - fn main() { - assert_eq!(bar::bar(), 1); - assert_eq!(baz::baz(), 2); - } - "#, - ) - .build(); - - let _baz = project() - .at("baz") - .file( - "Cargo.toml", - &format!( - r#" - [package] - name = "baz" - version = "0.0.0" - authors = [] - - [dependencies.bar] - git = '{}' - rev = "{}" - "#, - bar.url(), - rev2 - ), - ) - .file( - "src/lib.rs", - r#" - extern crate bar; - pub fn baz() -> i32 { bar::bar() } - "#, - ) - .build(); - - foo.cargo("build -v").run(); - assert!(foo.bin("foo").is_file()); - foo.process(&foo.bin("foo")).run(); -} - -#[cargo_test] fn recompilation() { let git_project = git::new("bar", |project| { project @@ -2795,7 +2711,7 @@ fn use_the_cli() { [UPDATING] git repository `[..]` [RUNNING] `git fetch [..]` From [..] - * [new ref] -> origin/HEAD + * [new ref] [..] -> origin/HEAD[..] [CHECKING] dep1 [..] [RUNNING] `rustc [..]` [CHECKING] foo [..] @@ -3421,6 +3337,9 @@ fn metadata_master_consistency() { "workspace_members": [ "foo 0.1.0 [..]" ], + "workspace_default_members": [ + "foo 0.1.0 [..]" + ], "resolve": { "nodes": [ { diff --git a/src/tools/cargo/tests/testsuite/git_shallow.rs b/src/tools/cargo/tests/testsuite/git_shallow.rs new file mode 100644 index 000000000..8045880cf --- /dev/null +++ b/src/tools/cargo/tests/testsuite/git_shallow.rs @@ -0,0 +1,831 @@ +use crate::git_gc::find_index; +use cargo_test_support::registry::Package; +use cargo_test_support::{basic_manifest, git, paths, project}; + +enum RepoMode { + Shallow, + Complete, +} + +#[cargo_test] +fn gitoxide_clones_shallow_two_revs_same_deps() { + perform_two_revs_same_deps(true) +} + +fn perform_two_revs_same_deps(shallow: bool) { + let bar = git::new("meta-dep", |project| { + project + .file("Cargo.toml", &basic_manifest("bar", "0.0.0")) + .file("src/lib.rs", "pub fn bar() -> i32 { 1 }") + }); + + let repo = git2::Repository::open(&bar.root()).unwrap(); + let rev1 = repo.revparse_single("HEAD").unwrap().id(); + + // Commit the changes and make sure we trigger a recompile + bar.change_file("src/lib.rs", "pub fn bar() -> i32 { 2 }"); + git::add(&repo); + let rev2 = git::commit(&repo); + + let foo = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.0.0" + authors = [] + + [dependencies.bar] + git = '{}' + rev = "{}" + + [dependencies.baz] + path = "../baz" + "#, + bar.url(), + rev1 + ), + ) + .file( + "src/main.rs", + r#" + extern crate bar; + extern crate baz; + + fn main() { + assert_eq!(bar::bar(), 1); + assert_eq!(baz::baz(), 2); + } + "#, + ) + .build(); + + let _baz = project() + .at("baz") + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "baz" + version = "0.0.0" + authors = [] + + [dependencies.bar] + git = '{}' + rev = "{}" + "#, + bar.url(), + rev2 + ), + ) + .file( + "src/lib.rs", + r#" + extern crate bar; + pub fn baz() -> i32 { bar::bar() } + "#, + ) + .build(); + + let args = if shallow { + "build -v -Zgitoxide=fetch,shallow-deps" + } else { + "build -v" + }; + foo.cargo(args) + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + assert!(foo.bin("foo").is_file()); + foo.process(&foo.bin("foo")).run(); +} + +#[cargo_test] +fn two_revs_same_deps() { + perform_two_revs_same_deps(false) +} + +#[cargo_test] +fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_with_git2_fetch( +) -> anyhow::Result<()> { + Package::new("bar", "1.0.0").publish(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = "1.0" + "#, + ) + .file("src/lib.rs", "") + .build(); + p.cargo("fetch") + .arg("-Zgitoxide=fetch,shallow-index") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + let shallow_repo = gix::open_opts(find_index(), gix::open::Options::isolated())?; + assert_eq!( + shallow_repo + .rev_parse_single("origin/HEAD")? + .ancestors() + .all()? + .count(), + 1, + "shallow clones always start at depth of 1 to minimize download size" + ); + assert!(shallow_repo.is_shallow()); + + Package::new("bar", "1.1.0").publish(); + p.cargo("update") + .env("__CARGO_USE_GITOXIDE_INSTEAD_OF_GIT2", "0") + .run(); + + let repo = gix::open_opts( + find_remote_index(RepoMode::Complete), + gix::open::Options::isolated(), + )?; + assert_eq!( + repo.rev_parse_single("origin/HEAD")? + .ancestors() + .all()? + .count(), + 3, + "an entirely new repo was cloned which is never shallow" + ); + assert!(!repo.is_shallow()); + Ok(()) +} + +#[cargo_test] +fn gitoxide_clones_git_dependency_with_shallow_protocol_and_git2_is_used_for_followup_fetches( +) -> anyhow::Result<()> { + // Example where an old lockfile with an explicit branch="master" in Cargo.toml. + Package::new("bar", "1.0.0").publish(); + let (bar, bar_repo) = git::new_repo("bar", |p| { + p.file("Cargo.toml", &basic_manifest("bar", "1.0.0")) + .file("src/lib.rs", "") + }); + + bar.change_file("src/lib.rs", "// change"); + git::add(&bar_repo); + git::commit(&bar_repo); + + { + let mut walk = bar_repo.revwalk()?; + walk.push_head()?; + assert_eq!( + walk.count(), + 2, + "original repo has initial commit and change commit" + ); + } + + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = {{ version = "1.0", git = "{}", branch = "master" }} + "#, + bar.url() + ), + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("update") + .arg("-Zgitoxide=fetch,shallow-deps") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + let db_clone = gix::open_opts( + find_bar_db(RepoMode::Shallow), + gix::open::Options::isolated(), + )?; + assert!(db_clone.is_shallow()); + assert_eq!( + db_clone + .rev_parse_single("origin/master")? + .ancestors() + .all()? + .count(), + 1, + "db clones are shallow and have a shortened history" + ); + + let dep_checkout = gix::open_opts( + find_lexicographically_first_bar_checkout(), + gix::open::Options::isolated(), + )?; + assert!(dep_checkout.is_shallow()); + assert_eq!( + dep_checkout.head_id()?.ancestors().all()?.count(), + 1, + "db checkouts are hard-linked clones with the shallow file copied separately." + ); + + bar.change_file("src/lib.rs", "// another change"); + git::add(&bar_repo); + git::commit(&bar_repo); + { + let mut walk = bar_repo.revwalk()?; + walk.push_head()?; + assert_eq!( + walk.count(), + 3, + "original repo has initial commit and change commit, and another change" + ); + } + + p.cargo("update") + .env("__CARGO_USE_GITOXIDE_INSTEAD_OF_GIT2", "0") + .run(); + + let db_clone = gix::open_opts( + find_bar_db(RepoMode::Complete), + gix::open::Options::isolated(), + )?; + assert_eq!( + db_clone + .rev_parse_single("origin/master")? + .ancestors() + .all()? + .count(), + 3, + "the db clone was re-initialized and has all commits" + ); + assert!( + !db_clone.is_shallow(), + "shallow-ness was removed as git2 does not support it" + ); + assert_eq!( + dep_checkout.head_id()?.ancestors().all()?.count(), + 1, + "the original dep checkout didn't change - there is a new one for each update we get locally" + ); + + let max_history_depth = glob::glob( + paths::home() + .join(".cargo/git/checkouts/bar-*/*/.git") + .to_str() + .unwrap(), + )? + .map(|path| -> anyhow::Result<usize> { + let dep_checkout = gix::open_opts(path?, gix::open::Options::isolated())?; + let depth = dep_checkout.head_id()?.ancestors().all()?.count(); + assert_eq!(dep_checkout.is_shallow(), depth == 1, "the first checkout is done with gitoxide and shallow, the second one is git2 non-shallow"); + Ok(depth) + }) + .map(Result::unwrap) + .max() + .expect("two checkout repos"); + + assert_eq!( + max_history_depth, 3, + "the new checkout sees all commits of the non-shallow DB repository" + ); + + Ok(()) +} + +#[cargo_test] +fn gitoxide_shallow_clone_followed_by_non_shallow_update() -> anyhow::Result<()> { + Package::new("bar", "1.0.0").publish(); + let (bar, bar_repo) = git::new_repo("bar", |p| { + p.file("Cargo.toml", &basic_manifest("bar", "1.0.0")) + .file("src/lib.rs", "") + }); + + bar.change_file("src/lib.rs", "// change"); + git::add(&bar_repo); + git::commit(&bar_repo); + + { + let mut walk = bar_repo.revwalk()?; + walk.push_head()?; + assert_eq!( + walk.count(), + 2, + "original repo has initial commit and change commit" + ); + } + + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = {{ version = "1.0", git = "{}", branch = "master" }} + "#, + bar.url() + ), + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("update") + .arg("-Zgitoxide=fetch,shallow-deps") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + let shallow_db_clone = gix::open_opts( + find_bar_db(RepoMode::Shallow), + gix::open::Options::isolated(), + )?; + assert!(shallow_db_clone.is_shallow()); + assert_eq!( + shallow_db_clone + .rev_parse_single("origin/master")? + .ancestors() + .all()? + .count(), + 1, + "db clones are shallow and have a shortened history" + ); + + let dep_checkout = gix::open_opts( + find_lexicographically_first_bar_checkout(), + gix::open::Options::isolated(), + )?; + assert!(dep_checkout.is_shallow()); + assert_eq!( + dep_checkout.head_id()?.ancestors().all()?.count(), + 1, + "db checkouts are hard-linked clones with the shallow file copied separately." + ); + + bar.change_file("src/lib.rs", "// another change"); + git::add(&bar_repo); + git::commit(&bar_repo); + { + let mut walk = bar_repo.revwalk()?; + walk.push_head()?; + assert_eq!( + walk.count(), + 3, + "original repo has initial commit and change commit, and another change" + ); + } + + p.cargo("update") + .arg("-Zgitoxide=fetch") // shallow-deps is omitted intentionally + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + let db_clone = gix::open_opts( + find_bar_db(RepoMode::Complete), + gix::open::Options::isolated(), + )?; + assert_eq!( + db_clone + .rev_parse_single("origin/master")? + .ancestors() + .all()? + .count(), + 3, + "we created an entirely new non-shallow clone" + ); + assert!(!db_clone.is_shallow()); + assert_eq!( + dep_checkout.head_id()?.ancestors().all()?.count(), + 1, + "the original dep checkout didn't change - there is a new one for each update we get locally" + ); + + let max_history_depth = glob::glob( + paths::home() + .join(".cargo/git/checkouts/bar-*/*/.git") + .to_str() + .unwrap(), + )? + .map(|path| -> anyhow::Result<usize> { + let path = path?; + let dep_checkout = gix::open_opts(&path, gix::open::Options::isolated())?; + assert_eq!( + dep_checkout.is_shallow(), + path.to_string_lossy().contains("-shallow"), + "checkouts of shallow db repos are shallow as well" + ); + let depth = dep_checkout.head_id()?.ancestors().all()?.count(); + Ok(depth) + }) + .map(Result::unwrap) + .max() + .expect("two checkout repos"); + + assert_eq!( + max_history_depth, 3, + "we see the previous shallow checkout as well as new new unshallow one" + ); + + Ok(()) +} + +#[cargo_test] +fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_fetch_maintains_shallowness( +) -> anyhow::Result<()> { + Package::new("bar", "1.0.0").publish(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = "1.0" + "#, + ) + .file("src/lib.rs", "") + .build(); + p.cargo("fetch") + .arg("-Zgitoxide=fetch,shallow-index") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + let repo = gix::open_opts(find_index(), gix::open::Options::isolated())?; + assert_eq!( + repo.rev_parse_single("origin/HEAD")? + .ancestors() + .all()? + .count(), + 1, + "shallow clones always start at depth of 1 to minimize download size" + ); + assert!(repo.is_shallow()); + + Package::new("bar", "1.1.0").publish(); + p.cargo("update") + .arg("-Zgitoxide=fetch,shallow-index") // NOTE: the flag needs to be consistent or else a different index is created + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + assert_eq!( + repo.rev_parse_single("origin/HEAD")? + .ancestors() + .all()? + .count(), + 1, + "subsequent shallow fetches wont' fetch what's inbetween, only the single commit that we need while leveraging existing commits" + ); + assert!(repo.is_shallow()); + + Package::new("bar", "1.2.0").publish(); + Package::new("bar", "1.3.0").publish(); + p.cargo("update") + .arg("-Zgitoxide=fetch,shallow-index") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + assert_eq!( + repo.rev_parse_single("origin/HEAD")? + .ancestors() + .all()? + .count(), + 1, + "shallow boundaries are moved with each fetch to maintain only a single commit of history" + ); + assert!(repo.is_shallow()); + + Ok(()) +} + +/// If there is shallow *and* non-shallow clones, non-shallow will naturally be returned due to sort order. +#[cargo_test] +fn gitoxide_clones_registry_without_shallow_protocol_and_follow_up_fetch_uses_shallowness( +) -> anyhow::Result<()> { + Package::new("bar", "1.0.0").publish(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = "1.0" + "#, + ) + .file("src/lib.rs", "") + .build(); + p.cargo("fetch") + .arg("-Zgitoxide=fetch") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + let repo = gix::open_opts(find_index(), gix::open::Options::isolated())?; + assert_eq!( + repo.rev_parse_single("origin/HEAD")? + .ancestors() + .all()? + .count(), + 2, + "initial commit and the first crate" + ); + assert!(!repo.is_shallow()); + + Package::new("bar", "1.1.0").publish(); + p.cargo("update") + .arg("-Zgitoxide=fetch,shallow-index") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + let shallow_repo = gix::open_opts( + find_remote_index(RepoMode::Shallow), + gix::open::Options::isolated(), + )?; + assert_eq!( + shallow_repo.rev_parse_single("origin/HEAD")? + .ancestors() + .all()? + .count(), + 1, + "the follow up clones an entirely new index which is now shallow and which is in its own location" + ); + assert!(shallow_repo.is_shallow()); + + Package::new("bar", "1.2.0").publish(); + Package::new("bar", "1.3.0").publish(); + p.cargo("update") + .arg("-Zgitoxide=fetch,shallow-index") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + assert_eq!( + shallow_repo + .rev_parse_single("origin/HEAD")? + .ancestors() + .all()? + .count(), + 1, + "subsequent shallow fetches wont' fetch what's inbetween, only the single commit that we need while leveraging existing commits" + ); + assert!(shallow_repo.is_shallow()); + + p.cargo("update") + .arg("-Zgitoxide=fetch") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + assert_eq!( + repo.rev_parse_single("origin/HEAD")? + .ancestors() + .all()? + .count(), + 5, + "we can separately fetch the non-shallow index as well and it sees all commits" + ); + + Ok(()) +} + +#[cargo_test] +fn gitoxide_git_dependencies_switch_from_branch_to_rev() -> anyhow::Result<()> { + // db exists from previous build, then dependency changes to refer to revision that isn't + // available in the shallow clone. + + let (bar, bar_repo) = git::new_repo("bar", |p| { + p.file("Cargo.toml", &basic_manifest("bar", "1.0.0")) + .file("src/lib.rs", "") + }); + + // this commit would not be available in a shallow clone. + let first_commit_pre_change = bar_repo.head().unwrap().target().unwrap(); + + bar.change_file("src/lib.rs", "// change"); + git::add(&bar_repo); + git::commit(&bar_repo); + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = {{ git = "{}", branch = "master" }} + "#, + bar.url(), + ), + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("check") + .arg("-Zgitoxide=fetch,shallow-deps") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + let db_clone = gix::open_opts( + find_bar_db(RepoMode::Shallow), + gix::open::Options::isolated(), + )?; + assert!(db_clone.is_shallow()); + + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = {{ git = "{}", rev = "{}" }} + "#, + bar.url(), + first_commit_pre_change + ), + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("check") + .arg("-Zgitoxide=fetch,shallow-deps") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + assert!( + db_clone.is_shallow(), + "we maintain shallowness and never unshallow" + ); + + Ok(()) +} + +#[cargo_test] +fn shallow_deps_work_with_revisions_and_branches_mixed_on_same_dependency() -> anyhow::Result<()> { + let (bar, bar_repo) = git::new_repo("bar", |p| { + p.file("Cargo.toml", &basic_manifest("bar", "1.0.0")) + .file("src/lib.rs", "") + }); + + // this commit would not be available in a shallow clone. + let first_commit_pre_change = bar_repo.head().unwrap().target().unwrap(); + + bar.change_file("src/lib.rs", "// change"); + git::add(&bar_repo); + git::commit(&bar_repo); + + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar-renamed = {{ package = "bar", git = "{}", rev = "{}" }} + bar = {{ git = "{}", branch = "master" }} + "#, + bar.url(), + first_commit_pre_change, + bar.url(), + ), + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("check") + .arg("-Zgitoxide=fetch,shallow-deps") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + let db_paths = glob::glob(paths::home().join(".cargo/git/db/bar-*").to_str().unwrap())? + .map(Result::unwrap) + .collect::<Vec<_>>(); + assert_eq!( + db_paths.len(), + 1, + "only one db checkout source is used per dependency" + ); + let db_clone = gix::open_opts(&db_paths[0], gix::open::Options::isolated())?; + assert!( + db_clone.is_shallow(), + "the repo is shallow while having all data it needs" + ); + + Ok(()) +} + +#[cargo_test] +fn gitoxide_clones_registry_with_shallow_protocol_and_aborts_and_updates_again( +) -> anyhow::Result<()> { + Package::new("bar", "1.0.0").publish(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = "1.0" + "#, + ) + .file("src/lib.rs", "") + .build(); + p.cargo("fetch") + .arg("-Zgitoxide=fetch,shallow-index") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + let repo = gix::open_opts(find_index(), gix::open::Options::isolated())?; + assert_eq!( + repo.rev_parse_single("origin/HEAD")? + .ancestors() + .all()? + .count(), + 1, + "shallow clones always start at depth of 1 to minimize download size" + ); + assert!(repo.is_shallow()); + let shallow_lock = repo.shallow_file().with_extension("lock"); + // adding a lock file and deleting the original simulates a left-over clone that was aborted, leaving a lock file + // in place without ever having moved it to the right location. + std::fs::write(&shallow_lock, &[])?; + std::fs::remove_file(repo.shallow_file())?; + + Package::new("bar", "1.1.0").publish(); + p.cargo("update") + .arg("-Zgitoxide=fetch,shallow-index") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + assert!(!shallow_lock.is_file(), "the repository was re-initialized"); + assert!(repo.is_shallow()); + assert_eq!( + repo.rev_parse_single("origin/HEAD")? + .ancestors() + .all()? + .count(), + 1, + "it's a fresh shallow clone - otherwise it would have 2 commits if the previous shallow clone would still be present" + ); + + Ok(()) +} + +fn find_lexicographically_first_bar_checkout() -> std::path::PathBuf { + glob::glob( + paths::home() + .join(".cargo/git/checkouts/bar-*/*/.git") + .to_str() + .unwrap(), + ) + .unwrap() + .next() + .unwrap() + .unwrap() + .to_owned() +} + +fn find_remote_index(mode: RepoMode) -> std::path::PathBuf { + glob::glob( + paths::home() + .join(".cargo/registry/index/*") + .to_str() + .unwrap(), + ) + .unwrap() + .map(Result::unwrap) + .filter(|p| p.to_string_lossy().ends_with("-shallow") == matches!(mode, RepoMode::Shallow)) + .next() + .unwrap() +} + +/// Find a checkout directory for bar, `shallow` or not. +fn find_bar_db(mode: RepoMode) -> std::path::PathBuf { + glob::glob(paths::home().join(".cargo/git/db/bar-*").to_str().unwrap()) + .unwrap() + .map(Result::unwrap) + .filter(|p| p.to_string_lossy().ends_with("-shallow") == matches!(mode, RepoMode::Shallow)) + .next() + .unwrap() + .to_owned() +} diff --git a/src/tools/cargo/tests/testsuite/https.rs b/src/tools/cargo/tests/testsuite/https.rs index 501eeae05..c7aec9111 100644 --- a/src/tools/cargo/tests/testsuite/https.rs +++ b/src/tools/cargo/tests/testsuite/https.rs @@ -30,7 +30,7 @@ fn self_signed_should_fail() { .build(); // I think the text here depends on the curl backend. let err_msg = if cfg!(target_os = "macos") { - "unexpected return value from ssl handshake -9806; class=Ssl (16)" + "untrusted connection error; class=Ssl (16); code=Certificate (-17)" } else if cfg!(unix) { "the SSL certificate is invalid; class=Ssl (16); code=Certificate (-17)" } else if cfg!(windows) { diff --git a/src/tools/cargo/tests/testsuite/inheritable_workspace_fields.rs b/src/tools/cargo/tests/testsuite/inheritable_workspace_fields.rs index 92c96b985..cc261a47f 100644 --- a/src/tools/cargo/tests/testsuite/inheritable_workspace_fields.rs +++ b/src/tools/cargo/tests/testsuite/inheritable_workspace_fields.rs @@ -201,6 +201,7 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. "readme": null, "readme_file": null, "repository": "https://github.com/example/example", + "rust_version": "1.60", "vers": "1.2.3" } "#, @@ -376,6 +377,7 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. "readme": null, "readme_file": null, "repository": null, + "rust_version": null, "vers": "0.2.0" } "#, @@ -503,6 +505,7 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. "readme": null, "readme_file": null, "repository": null, + "rust_version": null, "vers": "0.2.0" } "#, @@ -734,6 +737,7 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. "readme": "README.md", "readme_file": "../README.md", "repository": "https://github.com/example/example", + "rust_version": "1.60", "vers": "1.2.3" } "#, @@ -917,6 +921,7 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. "readme": null, "readme_file": null, "repository": null, + "rust_version": null, "vers": "0.2.0" } "#, @@ -1269,7 +1274,9 @@ fn error_workspace_dependency_looked_for_workspace_itself() { .with_stderr( "\ [WARNING] [CWD]/Cargo.toml: unused manifest key: workspace.dependencies.dep.workspace -[WARNING] [CWD]/Cargo.toml: dependency (dep) specified without providing a local path, Git repository, or version to use. This will be considered an error in future versions +[WARNING] [CWD]/Cargo.toml: dependency (dep) specified without providing a local path, Git repository, version, \ +or workspace dependency to use. \ +This will be considered an error in future versions [UPDATING] `dummy-registry` index [ERROR] no matching package named `dep` found location searched: registry `crates-io` @@ -1589,7 +1596,9 @@ fn cannot_inherit_in_patch() { .with_stderr( "\ [WARNING] [CWD]/Cargo.toml: unused manifest key: patch.crates-io.bar.workspace -[WARNING] [CWD]/Cargo.toml: dependency (bar) specified without providing a local path, Git repository, or version to use. This will be considered an error in future versions +[WARNING] [CWD]/Cargo.toml: dependency (bar) specified without providing a local path, Git repository, version, \ +or workspace dependency to use. \ +This will be considered an error in future versions [UPDATING] `dummy-registry` index [ERROR] failed to resolve patches for `https://github.com/rust-lang/crates.io-index` diff --git a/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/Cargo.toml b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/Cargo.toml new file mode 100644 index 000000000..b7a2e9036 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/Cargo.toml @@ -0,0 +1,21 @@ +[workspace] +members = [ + "crates/*", +] + +[workspace.package] +authors = ["Rustaceans"] +description = "foo" +edition = "2018" +homepage = "foo" +keywords = ["foo", "bar"] +readme = "README.md" +rust-version = "1.67.0" +categories = ["algorithms"] +documentation = "foo" +exclude = ["foo"] +include = ["foo"] +license = "MIT OR Apache-2.0" +publish = false +repository = "foo" +version = "1.2.3" diff --git a/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/README.md b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/README.md new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/README.md diff --git a/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/crates/foo/src/main.rs b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/crates/foo/src/main.rs new file mode 100644 index 000000000..43f0dac5e --- /dev/null +++ b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/crates/foo/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Check that our file is not overwritten") +} diff --git a/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/src/lib.rs b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/src/lib.rs new file mode 100644 index 000000000..7d12d9af8 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/mod.rs b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/mod.rs new file mode 100644 index 000000000..4e1dda845 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/mod.rs @@ -0,0 +1,22 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::curr_dir; +use cargo_test_support::CargoCommand; +use cargo_test_support::Project; + +#[cargo_test] +fn case() { + let project = Project::from_template(curr_dir!().join("in")); + let project_root = project.root(); + let cwd = &project_root; + + snapbox::cmd::Command::cargo_ui() + .arg("init") + .args(["crates/foo"]) + .current_dir(cwd) + .assert() + .success() + .stdout_matches_path(curr_dir!().join("stdout.log")) + .stderr_matches_path(curr_dir!().join("stderr.log")); + + assert_ui().subset_matches(curr_dir!().join("out"), &project_root); +} diff --git a/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/out/Cargo.toml b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/out/Cargo.toml new file mode 100644 index 000000000..b7a2e9036 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/out/Cargo.toml @@ -0,0 +1,21 @@ +[workspace] +members = [ + "crates/*", +] + +[workspace.package] +authors = ["Rustaceans"] +description = "foo" +edition = "2018" +homepage = "foo" +keywords = ["foo", "bar"] +readme = "README.md" +rust-version = "1.67.0" +categories = ["algorithms"] +documentation = "foo" +exclude = ["foo"] +include = ["foo"] +license = "MIT OR Apache-2.0" +publish = false +repository = "foo" +version = "1.2.3" diff --git a/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/out/crates/foo/Cargo.toml b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/out/crates/foo/Cargo.toml new file mode 100644 index 000000000..137ed1c87 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/out/crates/foo/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "foo" +authors.workspace = true +description.workspace = true +edition.workspace = true +homepage.workspace = true +keywords.workspace = true +readme.workspace = true +rust-version.workspace = true +categories.workspace = true +documentation.workspace = true +exclude.workspace = true +include.workspace = true +license.workspace = true +publish.workspace = true +repository.workspace = true +version.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/out/crates/foo/src/main.rs b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/out/crates/foo/src/main.rs new file mode 100644 index 000000000..43f0dac5e --- /dev/null +++ b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/out/crates/foo/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Check that our file is not overwritten") +} diff --git a/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/out/src/lib.rs b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/out/src/lib.rs new file mode 100644 index 000000000..7d12d9af8 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/out/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/stderr.log b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/stderr.log new file mode 100644 index 000000000..3847e4e4a --- /dev/null +++ b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/stderr.log @@ -0,0 +1 @@ + Created binary (application) package diff --git a/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/stdout.log b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/stdout.log new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/stdout.log diff --git a/src/tools/cargo/tests/testsuite/init/mod.rs b/src/tools/cargo/tests/testsuite/init/mod.rs index 99df9d39d..7853a1a0b 100644 --- a/src/tools/cargo/tests/testsuite/init/mod.rs +++ b/src/tools/cargo/tests/testsuite/init/mod.rs @@ -21,6 +21,7 @@ mod git_ignore_exists_no_conflicting_entries; mod ignores_failure_to_format_source; mod inferred_bin_with_git; mod inferred_lib_with_git; +mod inherit_workspace_package_table; mod invalid_dir_name; mod lib_already_exists_nosrc; mod lib_already_exists_src; diff --git a/src/tools/cargo/tests/testsuite/install.rs b/src/tools/cargo/tests/testsuite/install.rs index dd9844f17..9b881dfdc 100644 --- a/src/tools/cargo/tests/testsuite/install.rs +++ b/src/tools/cargo/tests/testsuite/install.rs @@ -1416,6 +1416,46 @@ fn path_install_workspace_root_despite_default_members() { } #[cargo_test] +fn git_install_workspace_root_despite_default_members() { + let p = git::repo(&paths::root().join("foo")) + .file( + "Cargo.toml", + r#" + [package] + name = "ws-root" + version = "0.1.0" + authors = [] + + [workspace] + members = ["ws-member"] + default-members = ["ws-member"] + "#, + ) + .file("src/main.rs", "fn main() {}") + .file( + "ws-member/Cargo.toml", + r#" + [package] + name = "ws-member" + version = "0.1.0" + authors = [] + "#, + ) + .file("ws-member/src/main.rs", "fn main() {}") + .build(); + + cargo_process("install --git") + .arg(p.url().to_string()) + .arg("ws-root") + .with_stderr_contains( + "[INSTALLED] package `ws-root v0.1.0 ([..])` (executable `ws-root[EXE]`)", + ) + // Particularly avoid "Installed package `ws-root v0.1.0 ([..]])` (executable `ws-member`)": + .with_stderr_does_not_contain("ws-member") + .run(); +} + +#[cargo_test] fn dev_dependencies_no_check() { Package::new("foo", "1.0.0").publish(); let p = project() @@ -2287,3 +2327,84 @@ fn sparse_install() { "#, ); } + +#[cargo_test] +fn self_referential() { + // Some packages build-dep on prior versions of themselves. + Package::new("foo", "0.0.1") + .file("src/lib.rs", "fn hello() {}") + .file("src/main.rs", "fn main() {}") + .file("build.rs", "fn main() {}") + .publish(); + Package::new("foo", "0.0.2") + .file("src/lib.rs", "fn hello() {}") + .file("src/main.rs", "fn main() {}") + .file("build.rs", "fn main() {}") + .build_dep("foo", "0.0.1") + .publish(); + + cargo_process("install foo") + .with_stderr( + "\ +[UPDATING] `[..]` index +[DOWNLOADING] crates ... +[DOWNLOADED] foo v0.0.2 (registry [..]) +[INSTALLING] foo v0.0.2 +[DOWNLOADING] crates ... +[DOWNLOADED] foo v0.0.1 (registry [..]) +[COMPILING] foo v0.0.1 +[COMPILING] foo v0.0.2 +[FINISHED] release [optimized] target(s) in [..] +[INSTALLING] [CWD]/home/.cargo/bin/foo[EXE] +[INSTALLED] package `foo v0.0.2` (executable `foo[EXE]`) +[WARNING] be sure to add `[..]` to your PATH to be able to run the installed binaries +", + ) + .run(); + assert_has_installed_exe(cargo_home(), "foo"); +} + +#[cargo_test] +fn ambiguous_registry_vs_local_package() { + // Correctly install 'foo' from a local package, even if that package also + // depends on a registry dependency named 'foo'. + Package::new("foo", "0.0.1") + .file("src/lib.rs", "fn hello() {}") + .publish(); + + let p = project() + .file("src/main.rs", "fn main() {}") + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + authors = [] + edition = "2021" + + [dependencies] + foo = "0.0.1" + "#, + ) + .build(); + + cargo_process("install --path") + .arg(p.root()) + .with_stderr( + "\ +[INSTALLING] foo v0.1.0 ([..]) +[UPDATING] `[..]` index +[DOWNLOADING] crates ... +[DOWNLOADED] foo v0.0.1 (registry [..]) +[COMPILING] foo v0.0.1 +[COMPILING] foo v0.1.0 ([..]) +[FINISHED] release [optimized] target(s) in [..] +[INSTALLING] [CWD]/home/.cargo/bin/foo[EXE] +[INSTALLED] package `foo v0.1.0 ([..])` (executable `foo[EXE]`) +[WARNING] be sure to add `[..]` to your PATH to be able to run the installed binaries +", + ) + .run(); + assert_has_installed_exe(cargo_home(), "foo"); +} diff --git a/src/tools/cargo/tests/testsuite/lints.rs b/src/tools/cargo/tests/testsuite/lints.rs new file mode 100644 index 000000000..fb31da30a --- /dev/null +++ b/src/tools/cargo/tests/testsuite/lints.rs @@ -0,0 +1,639 @@ +//! Tests for `[lints]` + +use cargo_test_support::project; +use cargo_test_support::registry::Package; + +#[cargo_test] +fn package_requires_option() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [lints.rust] + unsafe_code = "forbid" + "#, + ) + .file("src/lib.rs", "") + .build(); + + foo.cargo("check") + .with_stderr( + "\ +warning: unused manifest key `lints` (may be supported in a future version) + +this Cargo does not support nightly features, but if you +switch to nightly channel you can pass +`-Zlints` to enable this feature. +[CHECKING] [..] +[FINISHED] [..] +", + ) + .run(); +} + +#[cargo_test] +fn workspace_requires_option() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [workspace.lints.rust] + unsafe_code = "forbid" + "#, + ) + .file("src/lib.rs", "") + .build(); + + foo.cargo("check") + .with_stderr( + "\ +warning: [CWD]/Cargo.toml: unused manifest key `lints` (may be supported in a future version) + +this Cargo does not support nightly features, but if you +switch to nightly channel you can pass +`-Zlints` to enable this feature. +[CHECKING] [..] +[FINISHED] [..] +", + ) + .run(); +} + +#[cargo_test] +fn dependency_warning_ignored() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [dependencies] + bar.path = "../bar" + "#, + ) + .file("src/lib.rs", "") + .build(); + + let _bar = project() + .at("bar") + .file( + "Cargo.toml", + r#" + [package] + name = "bar" + version = "0.0.1" + authors = [] + + [lints.rust] + unsafe_code = "forbid" + "#, + ) + .file("src/lib.rs", "") + .build(); + + foo.cargo("check") + .with_stderr( + "\ +[CHECKING] [..] +[CHECKING] [..] +[FINISHED] [..] +", + ) + .run(); +} + +#[cargo_test] +fn malformed_on_stable() { + let foo = project() + .file( + "Cargo.toml", + r#" + lints = 20 + [package] + name = "foo" + version = "0.0.1" + authors = [] + + "#, + ) + .file("src/lib.rs", "") + .build(); + + foo.cargo("check") + .with_stderr( + "\ +warning: unused manifest key `lints` (may be supported in a future version) + +this Cargo does not support nightly features, but if you +switch to nightly channel you can pass +`-Zlints` to enable this feature. +[CHECKING] [..] +[FINISHED] [..] +", + ) + .run(); +} + +#[cargo_test] +fn malformed_on_nightly() { + let foo = project() + .file( + "Cargo.toml", + r#" + lints = 20 + [package] + name = "foo" + version = "0.0.1" + authors = [] + + "#, + ) + .file("src/lib.rs", "") + .build(); + + foo.cargo("check -Zlints") + .masquerade_as_nightly_cargo(&["lints"]) + .with_status(101) + .with_stderr( + "\ +error: failed to parse manifest[..] + +Caused by: + invalid type: integer `20`, expected a map +", + ) + .run(); +} + +#[cargo_test] +fn fail_on_invalid_tool() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [workspace.lints.super-awesome-linter] + unsafe_code = "forbid" + "#, + ) + .file("src/lib.rs", "") + .build(); + + foo.cargo("check -Zlints") + .masquerade_as_nightly_cargo(&["lints"]) + .with_status(101) + .with_stderr( + "\ +[..] + +Caused by: + unsupported `super-awesome-linter` in `[lints]`, must be one of rust, clippy, rustdoc +", + ) + .run(); +} + +#[cargo_test] +fn fail_on_tool_injection() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [workspace.lints.rust] + "clippy::cyclomatic_complexity" = "warn" + "#, + ) + .file("src/lib.rs", "") + .build(); + + foo.cargo("check -Zlints") + .masquerade_as_nightly_cargo(&["lints"]) + .with_status(101) + .with_stderr( + "\ +[..] + +Caused by: + `lints.rust.clippy::cyclomatic_complexity` is not valid lint name; try `lints.clippy.cyclomatic_complexity` +", + ) + .run(); +} + +#[cargo_test] +fn fail_on_redundant_tool() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [workspace.lints.rust] + "rust::unsafe_code" = "forbid" + "#, + ) + .file("src/lib.rs", "") + .build(); + + foo.cargo("check -Zlints") + .masquerade_as_nightly_cargo(&["lints"]) + .with_status(101) + .with_stderr( + "\ +[..] + +Caused by: + `lints.rust.rust::unsafe_code` is not valid lint name; try `lints.rust.unsafe_code` +", + ) + .run(); +} + +#[cargo_test] +fn fail_on_conflicting_tool() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [workspace.lints.rust] + "super-awesome-tool::unsafe_code" = "forbid" + "#, + ) + .file("src/lib.rs", "") + .build(); + + foo.cargo("check -Zlints") + .masquerade_as_nightly_cargo(&["lints"]) + .with_status(101) + .with_stderr( + "\ +[..] + +Caused by: + `lints.rust.super-awesome-tool::unsafe_code` is not a valid lint name +", + ) + .run(); +} + +#[cargo_test] +fn package_lint_deny() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [lints.rust] + "unsafe_code" = "deny" + "#, + ) + .file( + "src/lib.rs", + " +pub fn foo(num: i32) -> u32 { + unsafe { std::mem::transmute(num) } +} +", + ) + .build(); + + foo.cargo("check -Zlints") + .masquerade_as_nightly_cargo(&["lints"]) + .with_status(101) + .with_stderr_contains( + "\ +error: usage of an `unsafe` block +", + ) + .run(); +} + +#[cargo_test] +fn workspace_lint_deny() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [lints] + workspace = true + + [workspace.lints.rust] + "unsafe_code" = "deny" + "#, + ) + .file( + "src/lib.rs", + " +pub fn foo(num: i32) -> u32 { + unsafe { std::mem::transmute(num) } +} +", + ) + .build(); + + foo.cargo("check -Zlints") + .masquerade_as_nightly_cargo(&["lints"]) + .with_status(101) + .with_stderr_contains( + "\ +error: usage of an `unsafe` block +", + ) + .run(); +} + +#[cargo_test] +fn attribute_has_precedence() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [lints.rust] + "unsafe_code" = "deny" + "#, + ) + .file( + "src/lib.rs", + " +#![allow(unsafe_code)] + +pub fn foo(num: i32) -> u32 { + unsafe { std::mem::transmute(num) } +} +", + ) + .build(); + + foo.cargo("check -Zlints") + .arg("-v") // Show order of rustflags on failure + .masquerade_as_nightly_cargo(&["lints"]) + .run(); +} + +#[cargo_test] +fn rustflags_has_precedence() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [lints.rust] + "unsafe_code" = "deny" + "#, + ) + .file( + "src/lib.rs", + " +pub fn foo(num: i32) -> u32 { + unsafe { std::mem::transmute(num) } +} +", + ) + .build(); + + foo.cargo("check -Zlints") + .arg("-v") // Show order of rustflags on failure + .env("RUSTFLAGS", "-Aunsafe_code") + .masquerade_as_nightly_cargo(&["lints"]) + .run(); +} + +#[cargo_test] +fn profile_rustflags_has_precedence() { + let foo = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["profile-rustflags"] + + [package] + name = "foo" + version = "0.0.1" + + [lints.rust] + "unsafe_code" = "deny" + + [profile.dev] + rustflags = ["-A", "unsafe_code"] + "#, + ) + .file( + "src/lib.rs", + " +pub fn foo(num: i32) -> u32 { + unsafe { std::mem::transmute(num) } +} +", + ) + .build(); + + foo.cargo("check -Zlints") + .arg("-v") // Show order of rustflags on failure + .masquerade_as_nightly_cargo(&["lints", "profile-rustflags"]) + .run(); +} + +#[cargo_test] +fn build_rustflags_has_precedence() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + + [lints.rust] + "unsafe_code" = "deny" + "#, + ) + .file( + ".cargo/config.toml", + r#" + [build] + rustflags = ["-A", "unsafe_code"] +"#, + ) + .file( + "src/lib.rs", + " +pub fn foo(num: i32) -> u32 { + unsafe { std::mem::transmute(num) } +} +", + ) + .build(); + + foo.cargo("check -Zlints") + .arg("-v") // Show order of rustflags on failure + .masquerade_as_nightly_cargo(&["lints"]) + .run(); +} + +#[cargo_test] +fn without_priority() { + Package::new("reg-dep", "1.0.0").publish(); + + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + edition = "2018" + authors = [] + + [dependencies] + reg-dep = "1.0.0" + + [lints.rust] + "rust-2018-idioms" = "deny" + "unused-extern-crates" = "allow" + "#, + ) + .file( + "src/lib.rs", + " +extern crate reg_dep; + +pub fn foo() -> u32 { + 2 +} +", + ) + .build(); + + foo.cargo("check -Zlints") + .masquerade_as_nightly_cargo(&["lints"]) + .with_status(101) + .with_stderr_contains( + "\ +error: unused extern crate +", + ) + .run(); +} + +#[cargo_test] +fn with_priority() { + Package::new("reg-dep", "1.0.0").publish(); + + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + edition = "2018" + authors = [] + + [dependencies] + reg-dep = "1.0.0" + + [lints.rust] + "rust-2018-idioms" = { level = "deny", priority = -1 } + "unused-extern-crates" = "allow" + "#, + ) + .file( + "src/lib.rs", + " +extern crate reg_dep; + +pub fn foo() -> u32 { + 2 +} +", + ) + .build(); + + foo.cargo("check -Zlints") + .masquerade_as_nightly_cargo(&["lints"]) + .run(); +} + +#[cargo_test] +fn rustdoc_lint() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [lints.rustdoc] + broken_intra_doc_links = "deny" + "#, + ) + .file( + "src/lib.rs", + " +/// [`bar`] doesn't exist +pub fn foo() -> u32 { +} +", + ) + .build(); + + foo.cargo("doc -Zlints") + .masquerade_as_nightly_cargo(&["lints"]) + .with_status(101) + .with_stderr_contains( + "\ +error: unresolved link to `bar` +", + ) + .run(); +} diff --git a/src/tools/cargo/tests/testsuite/main.rs b/src/tools/cargo/tests/testsuite/main.rs index a1e293acd..170a22667 100644 --- a/src/tools/cargo/tests/testsuite/main.rs +++ b/src/tools/cargo/tests/testsuite/main.rs @@ -24,6 +24,7 @@ mod cargo_command; mod cargo_config; mod cargo_env_config; mod cargo_features; +mod cargo_new; mod cargo_remove; mod cargo_targets; mod cfg; @@ -59,6 +60,7 @@ mod generate_lockfile; mod git; mod git_auth; mod git_gc; +mod git_shallow; mod glob_targets; mod help; mod https; @@ -67,6 +69,7 @@ mod init; mod install; mod install_upgrade; mod jobserver; +mod lints; mod list_availables; mod local_registry; mod locate_project; @@ -119,6 +122,7 @@ mod rustdoc; mod rustdoc_extern_html; mod rustdocflags; mod rustflags; +mod rustup; mod search; mod shell_quoting; mod source_replacement; diff --git a/src/tools/cargo/tests/testsuite/metadata.rs b/src/tools/cargo/tests/testsuite/metadata.rs index 547916e7a..ac2cec396 100644 --- a/src/tools/cargo/tests/testsuite/metadata.rs +++ b/src/tools/cargo/tests/testsuite/metadata.rs @@ -65,6 +65,7 @@ fn cargo_metadata_simple() { } ], "workspace_members": ["foo 0.5.0 (path+file:[..]foo)"], + "workspace_default_members": ["foo 0.5.0 (path+file:[..]foo)"], "resolve": { "nodes": [ { @@ -164,6 +165,7 @@ crate-type = ["lib", "staticlib"] } ], "workspace_members": ["foo 0.5.0 (path+file:[..]foo)"], + "workspace_default_members": ["foo 0.5.0 (path+file:[..]foo)"], "resolve": { "nodes": [ { @@ -257,6 +259,7 @@ optional_feat = [] } ], "workspace_members": ["foo 0.5.0 (path+file:[..]foo)"], + "workspace_default_members": ["foo 0.5.0 (path+file:[..]foo)"], "resolve": { "nodes": [ { @@ -587,6 +590,9 @@ fn cargo_metadata_with_deps_and_version() { "workspace_members": [ "foo 0.5.0 (path+file:[..]foo)" ], + "workspace_default_members": [ + "foo 0.5.0 (path+file:[..]foo)" + ], "workspace_root": "[..]/foo", "metadata": null }"#, @@ -668,6 +674,9 @@ name = "ex" "workspace_members": [ "foo 0.1.0 (path+file:[..]foo)" ], + "workspace_default_members": [ + "foo 0.1.0 (path+file:[..]foo)" + ], "resolve": { "root": "foo 0.1.0 (path+file://[..]foo)", "nodes": [ @@ -763,6 +772,9 @@ crate-type = ["rlib", "dylib"] "workspace_members": [ "foo 0.1.0 (path+file:[..]foo)" ], + "workspace_default_members": [ + "foo 0.1.0 (path+file:[..]foo)" + ], "resolve": { "root": "foo 0.1.0 (path+file://[..]foo)", "nodes": [ @@ -892,6 +904,7 @@ fn workspace_metadata() { } ], "workspace_members": ["bar 0.5.0 (path+file:[..]bar)", "baz 0.5.0 (path+file:[..]baz)"], + "workspace_default_members": ["bar 0.5.0 (path+file:[..]bar)", "baz 0.5.0 (path+file:[..]baz)"], "resolve": { "nodes": [ { @@ -1123,6 +1136,11 @@ fn workspace_metadata_with_dependencies_no_deps() { "artifact 0.5.0 (path+file:[..]/foo/artifact)", "baz 0.5.0 (path+file:[..]baz)" ], + "workspace_default_members": [ + "bar 0.5.0 (path+file:[..]bar)", + "artifact 0.5.0 (path+file:[..]/foo/artifact)", + "baz 0.5.0 (path+file:[..]baz)" + ], "resolve": null, "target_directory": "[..]foo/target", "version": 1, @@ -1755,6 +1773,12 @@ fn workspace_metadata_with_dependencies_and_resolve() { "bin-only-artifact 0.5.0 (path+file://[..]/foo/bin-only-artifact)", "non-artifact 0.5.0 (path+file://[..]/foo/non-artifact)" ], + "workspace_default_members": [ + "bar 0.5.0 (path+file://[..]/foo/bar)", + "artifact 0.5.0 (path+file://[..]/foo/artifact)", + "bin-only-artifact 0.5.0 (path+file://[..]/foo/bin-only-artifact)", + "non-artifact 0.5.0 (path+file://[..]/foo/non-artifact)" + ], "workspace_root": "[..]/foo" } "#, @@ -1953,6 +1977,7 @@ const MANIFEST_OUTPUT: &str = r#" "documentation": null }], "workspace_members": [ "foo 0.5.0 (path+file:[..]foo)" ], + "workspace_default_members": [ "foo 0.5.0 (path+file:[..]foo)" ], "resolve": null, "target_directory": "[..]foo/target", "version": 1, @@ -2147,6 +2172,7 @@ fn package_metadata() { } ], "workspace_members": ["foo[..]"], + "workspace_default_members": ["foo[..]"], "resolve": null, "target_directory": "[..]foo/target", "version": 1, @@ -2222,6 +2248,7 @@ fn package_publish() { } ], "workspace_members": ["foo[..]"], + "workspace_default_members": ["foo[..]"], "resolve": null, "target_directory": "[..]foo/target", "version": 1, @@ -2317,6 +2344,9 @@ fn cargo_metadata_path_to_cargo_toml_project() { "workspace_members": [ "bar 0.5.0 (path+file:[..])" ], + "workspace_default_members": [ + "bar 0.5.0 (path+file:[..])" + ], "workspace_root": "[..]", "metadata": null } @@ -2405,6 +2435,9 @@ fn package_edition_2018() { "workspace_members": [ "foo 0.1.0 (path+file:[..])" ], + "workspace_default_members": [ + "foo 0.1.0 (path+file:[..])" + ], "workspace_root": "[..]", "metadata": null } @@ -2553,6 +2586,9 @@ fn target_edition_2018() { "workspace_members": [ "foo 0.1.0 (path+file:[..])" ], + "workspace_default_members": [ + "foo 0.1.0 (path+file:[..])" + ], "workspace_root": "[..]", "metadata": null } @@ -2789,6 +2825,9 @@ fn rename_dependency() { "workspace_members": [ "foo 0.0.1[..]" ], + "workspace_default_members": [ + "foo 0.0.1[..]" + ], "workspace_root": "[..]", "metadata": null }"#, @@ -2889,6 +2928,9 @@ fn metadata_links() { "workspace_members": [ "foo 0.5.0 [..]" ], + "workspace_default_members": [ + "foo 0.5.0 [..]" + ], "workspace_root": "[..]/foo", "metadata": null } @@ -2979,6 +3021,9 @@ fn deps_with_bin_only() { "workspace_members": [ "foo 0.1.0 ([..])" ], + "workspace_default_members": [ + "foo 0.1.0 ([..])" + ], "resolve": { "nodes": [ { @@ -3358,6 +3403,9 @@ fn filter_platform() { "workspace_members": [ "foo 0.1.0 (path+file:[..]foo)" ], + "workspace_default_members": [ + "foo 0.1.0 (path+file:[..]foo)" + ], "resolve": { "nodes": [ { @@ -3477,6 +3525,7 @@ fn filter_platform() { $NORMAL_DEP ], "workspace_members": "{...}", + "workspace_default_members": "{...}", "resolve": { "nodes": [ { @@ -3558,6 +3607,7 @@ fn filter_platform() { $NORMAL_DEP ], "workspace_members": "{...}", + "workspace_default_members": "{...}", "resolve": { "nodes": [ { @@ -3642,6 +3692,7 @@ fn filter_platform() { $NORMAL_DEP ], "workspace_members": "{...}", + "workspace_default_members": "{...}", "resolve": { "nodes": [ { @@ -3756,6 +3807,7 @@ fn dep_kinds() { { "packages": "{...}", "workspace_members": "{...}", + "workspace_default_members": "{...}", "target_directory": "{...}", "version": 1, "workspace_root": "{...}", @@ -3871,6 +3923,7 @@ fn dep_kinds_workspace() { { "packages": "{...}", "workspace_members": "{...}", + "workspace_default_members": "{...}", "target_directory": "[..]/foo/target", "version": 1, "workspace_root": "[..]/foo", @@ -4184,6 +4237,11 @@ fn workspace_metadata_with_dependencies_no_deps_artifact() { "artifact 0.5.0 (path+file://[..]/foo/artifact)", "baz 0.5.0 (path+file://[..]/foo/baz)" ], + "workspace_default_members": [ + "bar 0.5.0 (path+file://[..]/foo/bar)", + "artifact 0.5.0 (path+file://[..]/foo/artifact)", + "baz 0.5.0 (path+file://[..]/foo/baz)" + ], "workspace_root": "[..]/foo" } "#, diff --git a/src/tools/cargo/tests/testsuite/mock-std/library/sysroot/Cargo.toml b/src/tools/cargo/tests/testsuite/mock-std/library/sysroot/Cargo.toml new file mode 100644 index 000000000..615c894db --- /dev/null +++ b/src/tools/cargo/tests/testsuite/mock-std/library/sysroot/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "sysroot" +version = "0.1.0" +edition = "2018" + +[dependencies] +proc_macro = { path = "../proc_macro" } +std = { path = "../std" } +test = { path = "../test" } + +[features] +panic-unwind = [] +backtrace = [] +feature1 = ["std/feature1"] +default = [] diff --git a/src/tools/cargo/tests/testsuite/mock-std/library/sysroot/src/lib.rs b/src/tools/cargo/tests/testsuite/mock-std/library/sysroot/src/lib.rs new file mode 100644 index 000000000..7215576fc --- /dev/null +++ b/src/tools/cargo/tests/testsuite/mock-std/library/sysroot/src/lib.rs @@ -0,0 +1 @@ +// Intentionally left blank. diff --git a/src/tools/cargo/tests/testsuite/mock-std/library/test/Cargo.toml b/src/tools/cargo/tests/testsuite/mock-std/library/test/Cargo.toml index 299db7bfd..b9f51eda7 100644 --- a/src/tools/cargo/tests/testsuite/mock-std/library/test/Cargo.toml +++ b/src/tools/cargo/tests/testsuite/mock-std/library/test/Cargo.toml @@ -5,14 +5,7 @@ authors = ["Alex Crichton <alex@alexcrichton.com>"] edition = "2018" [dependencies] -proc_macro = { path = "../proc_macro" } std = { path = "../std" } panic_unwind = { path = "../panic_unwind" } compiler_builtins = { path = "../compiler_builtins" } registry-dep-using-std = { version = "*", features = ['mockbuild'] } - -[features] -panic-unwind = [] -backtrace = [] -feature1 = ["std/feature1"] -default = [] diff --git a/src/tools/cargo/tests/testsuite/offline.rs b/src/tools/cargo/tests/testsuite/offline.rs index fe54fc59d..5f164dbeb 100644 --- a/src/tools/cargo/tests/testsuite/offline.rs +++ b/src/tools/cargo/tests/testsuite/offline.rs @@ -3,6 +3,7 @@ use cargo_test_support::{ basic_manifest, git, main_file, path2url, project, registry::{Package, RegistryBuilder}, + Execs, }; use std::fs; @@ -377,6 +378,15 @@ fn update_offline_not_cached_git() { #[cargo_test] fn cargo_compile_offline_with_cached_git_dep() { + compile_offline_with_cached_git_dep(false) +} + +#[cargo_test] +fn gitoxide_cargo_compile_offline_with_cached_git_dep_shallow_dep() { + compile_offline_with_cached_git_dep(true) +} + +fn compile_offline_with_cached_git_dep(shallow: bool) { let git_project = git::new("dep1", |project| { project .file("Cargo.toml", &basic_manifest("dep1", "0.5.0")) @@ -420,7 +430,17 @@ fn cargo_compile_offline_with_cached_git_dep() { ) .file("src/main.rs", "fn main(){}") .build(); - prj.cargo("build").run(); + let maybe_use_shallow = |mut cargo: Execs| -> Execs { + if shallow { + cargo + .arg("-Zgitoxide=fetch,shallow-deps") + .masquerade_as_nightly_cargo(&[ + "unstable features must be available for -Z gitoxide", + ]); + } + cargo + }; + maybe_use_shallow(prj.cargo("build")).run(); prj.change_file( "Cargo.toml", @@ -438,7 +458,7 @@ fn cargo_compile_offline_with_cached_git_dep() { rev2 ), ); - prj.cargo("build").run(); + maybe_use_shallow(prj.cargo("build")).run(); let p = project() .file( @@ -463,15 +483,15 @@ fn cargo_compile_offline_with_cached_git_dep() { let git_root = git_project.root(); - p.cargo("build --offline") - .with_stderr(format!( - "\ + let mut cargo = p.cargo("build --offline"); + cargo.with_stderr(format!( + "\ [COMPILING] dep1 v0.5.0 ({}#[..]) [COMPILING] foo v0.5.0 ([CWD]) [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]", - path2url(git_root), - )) - .run(); + path2url(git_root), + )); + maybe_use_shallow(cargo).run(); assert!(p.bin("foo").is_file()); @@ -496,7 +516,7 @@ fn cargo_compile_offline_with_cached_git_dep() { ), ); - p.cargo("build --offline").run(); + maybe_use_shallow(p.cargo("build --offline")).run(); p.process(&p.bin("foo")) .with_stdout("hello from cached git repo rev1\n") .run(); diff --git a/src/tools/cargo/tests/testsuite/package.rs b/src/tools/cargo/tests/testsuite/package.rs index 14bac6618..3b4328242 100644 --- a/src/tools/cargo/tests/testsuite/package.rs +++ b/src/tools/cargo/tests/testsuite/package.rs @@ -1775,6 +1775,142 @@ fn exclude_dot_files_and_directories_by_default() { } #[cargo_test] +fn empty_readme_path() { + // Warn but don't fail if `readme` is empty. + // Issue #11522. + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "1.0.0" + readme = "" + license = "MIT" + description = "foo" + homepage = "foo" + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("package --no-verify") + .with_stderr( + "\ +[WARNING] readme `` does not appear to exist (relative to `[..]/foo`). +Please update the readme setting in the manifest at `[..]/foo/Cargo.toml` +This may become a hard error in the future. +[PACKAGING] foo v1.0.0 ([..]/foo) +[PACKAGED] [..] files, [..] ([..] compressed) +", + ) + .run(); +} + +#[cargo_test] +fn invalid_readme_path() { + // Warn but don't fail if `readme` path is invalid. + // Issue #11522. + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "1.0.0" + readme = "DOES-NOT-EXIST" + license = "MIT" + description = "foo" + homepage = "foo" + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("package --no-verify") + .with_stderr( + "\ +[WARNING] readme `DOES-NOT-EXIST` does not appear to exist (relative to `[..]/foo`). +Please update the readme setting in the manifest at `[..]/foo/Cargo.toml` +This may become a hard error in the future. +[PACKAGING] foo v1.0.0 ([..]/foo) +[PACKAGED] [..] files, [..] ([..] compressed) +", + ) + .run(); +} + +#[cargo_test] +fn readme_or_license_file_is_dir() { + // Test warning when `readme` or `license-file` is a directory, not a file. + // Issue #11522. + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "1.0.0" + readme = "./src" + license-file = "./src" + description = "foo" + homepage = "foo" + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("package --no-verify") + .with_stderr( + "\ +[WARNING] license-file `./src` does not appear to exist (relative to `[..]/foo`). +Please update the license-file setting in the manifest at `[..]/foo/Cargo.toml` +This may become a hard error in the future. +[WARNING] readme `./src` does not appear to exist (relative to `[..]/foo`). +Please update the readme setting in the manifest at `[..]/foo/Cargo.toml` +This may become a hard error in the future. +[PACKAGING] foo v1.0.0 ([..]/foo) +[PACKAGED] [..] files, [..] ([..] compressed) +", + ) + .run(); +} + +#[cargo_test] +fn empty_license_file_path() { + // Warn but don't fail if license-file is empty. + // Issue #11522. + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "1.0.0" + license-file = "" + description = "foo" + homepage = "foo" + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("package --no-verify") + .with_stderr( + "\ +[WARNING] manifest has no license or license-file. +See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. +[WARNING] license-file `` does not appear to exist (relative to `[..]/foo`). +Please update the license-file setting in the manifest at `[..]/foo/Cargo.toml` +This may become a hard error in the future. +[PACKAGING] foo v1.0.0 ([..]/foo) +[PACKAGED] [..] files, [..] ([..] compressed) +", + ) + .run(); +} + +#[cargo_test] fn invalid_license_file_path() { // Test warning when license-file points to a non-existent file. let p = project() @@ -2400,6 +2536,91 @@ See [..] } #[cargo_test] +fn workspace_noconflict_readme() { + let p = project() + .file( + "Cargo.toml", + r#" + [workspace] + members = ["bar"] + "#, + ) + .file("README.md", "workspace readme") + .file( + "bar/Cargo.toml", + r#" + [package] + name = "bar" + version = "0.0.1" + repository = "https://github.com/bar/bar" + authors = [] + license = "MIT" + description = "bar" + readme = "../README.md" + workspace = ".." + "#, + ) + .file("bar/src/main.rs", "fn main() {}") + .file("bar/example/README.md", "# example readmdBar") + .build(); + + p.cargo("package") + .with_stderr( + "\ +[PACKAGING] bar v0.0.1 ([CWD]/bar) +[VERIFYING] bar v0.0.1 ([CWD]/bar) +[COMPILING] bar v0.0.1 ([CWD]/[..]) +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +[PACKAGED] [..] files, [..] ([..] compressed) +", + ) + .run(); +} + +#[cargo_test] +fn workspace_conflict_readme() { + let p = project() + .file( + "Cargo.toml", + r#" + [workspace] + members = ["bar"] + "#, + ) + .file("README.md", "workspace readme") + .file( + "bar/Cargo.toml", + r#" + [package] + name = "bar" + version = "0.0.1" + repository = "https://github.com/bar/bar" + authors = [] + license = "MIT" + description = "bar" + readme = "../README.md" + workspace = ".." + "#, + ) + .file("bar/src/main.rs", "fn main() {}") + .file("bar/README.md", "# workspace member: Bar") + .build(); + + p.cargo("package") + .with_stderr( + "\ +warning: readme `../README.md` appears to be a path outside of the package, but there is already a file named `README.md` in the root of the package. The archived crate will contain the copy in the root of the package. Update the readme to point to the path relative to the root of the package to remove this warning. +[PACKAGING] bar v0.0.1 ([CWD]/bar) +[VERIFYING] bar v0.0.1 ([CWD]/bar) +[COMPILING] bar v0.0.1 ([CWD]/[..]) +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +[PACKAGED] [..] files, [..] ([..] compressed) +", + ) + .run(); +} + +#[cargo_test] fn workspace_overrides_resolver() { let p = project() .file( diff --git a/src/tools/cargo/tests/testsuite/patch.rs b/src/tools/cargo/tests/testsuite/patch.rs index 681c02416..f2f077d7d 100644 --- a/src/tools/cargo/tests/testsuite/patch.rs +++ b/src/tools/cargo/tests/testsuite/patch.rs @@ -2466,7 +2466,11 @@ fn can_update_with_alt_reg() { } #[cargo_test] -fn old_git_patch() { +fn gitoxide_clones_shallow_old_git_patch() { + perform_old_git_patch(true) +} + +fn perform_old_git_patch(shallow: bool) { // Example where an old lockfile with an explicit branch="master" in Cargo.toml. Package::new("bar", "1.0.0").publish(); let (bar, bar_repo) = git::new_repo("bar", |p| { @@ -2524,7 +2528,13 @@ dependencies = [ git::commit(&bar_repo); // This *should* keep the old lock. - p.cargo("tree") + let mut cargo = p.cargo("tree"); + if shallow { + cargo + .arg("-Zgitoxide=fetch,shallow-deps") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]); + } + cargo // .env("CARGO_LOG", "trace") .with_stderr( "\ @@ -2542,6 +2552,11 @@ foo v0.1.0 [..] .run(); } +#[cargo_test] +fn old_git_patch() { + perform_old_git_patch(false) +} + // From https://github.com/rust-lang/cargo/issues/7463 #[cargo_test] fn patch_eq_conflict_panic() { diff --git a/src/tools/cargo/tests/testsuite/profile_config.rs b/src/tools/cargo/tests/testsuite/profile_config.rs index c59ed7a97..cf9807964 100644 --- a/src/tools/cargo/tests/testsuite/profile_config.rs +++ b/src/tools/cargo/tests/testsuite/profile_config.rs @@ -1,5 +1,6 @@ //! Tests for profiles defined in config files. +use cargo::util::toml::TomlDebugInfo; use cargo_test_support::paths::CargoPathExt; use cargo_test_support::registry::Package; use cargo_test_support::{basic_lib_manifest, paths, project}; @@ -436,7 +437,7 @@ fn named_config_profile() { assert_eq!(p.name, "foo"); assert_eq!(p.codegen_units, Some(2)); // "foo" from config assert_eq!(p.opt_level, "1"); // "middle" from manifest - assert_eq!(p.debuginfo.to_option(), Some(1)); // "bar" from config + assert_eq!(p.debuginfo.to_option(), Some(TomlDebugInfo::Limited)); // "bar" from config assert_eq!(p.debug_assertions, true); // "dev" built-in (ignore build-override) assert_eq!(p.overflow_checks, true); // "dev" built-in (ignore package override) @@ -445,7 +446,7 @@ fn named_config_profile() { assert_eq!(bo.name, "foo"); assert_eq!(bo.codegen_units, Some(6)); // "foo" build override from config assert_eq!(bo.opt_level, "0"); // default to zero - assert_eq!(bo.debuginfo.to_option(), Some(1)); // SAME as normal + assert_eq!(bo.debuginfo.to_option(), Some(TomlDebugInfo::Limited)); // SAME as normal assert_eq!(bo.debug_assertions, false); // "foo" build override from manifest assert_eq!(bo.overflow_checks, true); // SAME as normal @@ -454,7 +455,7 @@ fn named_config_profile() { assert_eq!(po.name, "foo"); assert_eq!(po.codegen_units, Some(7)); // "foo" package override from config assert_eq!(po.opt_level, "1"); // SAME as normal - assert_eq!(po.debuginfo.to_option(), Some(1)); // SAME as normal + assert_eq!(po.debuginfo.to_option(), Some(TomlDebugInfo::Limited)); // SAME as normal assert_eq!(po.debug_assertions, true); // SAME as normal assert_eq!(po.overflow_checks, false); // "middle" package override from manifest } diff --git a/src/tools/cargo/tests/testsuite/profile_targets.rs b/src/tools/cargo/tests/testsuite/profile_targets.rs index b3235972c..0449e8ab3 100644 --- a/src/tools/cargo/tests/testsuite/profile_targets.rs +++ b/src/tools/cargo/tests/testsuite/profile_targets.rs @@ -83,16 +83,16 @@ fn profile_selection_build() { // - bdep `panic` is not set because it thinks `build.rs` is a plugin. // - build_script_build is built without panic because it thinks `build.rs` is a plugin. // - We make sure that the build dependencies bar, bdep, and build.rs - // are built without debuginfo. + // are built with debuginfo=0. p.cargo("build -vv") .with_stderr_unordered("\ [COMPILING] bar [..] [RUNNING] `[..] rustc --crate-name bar bar/src/lib.rs [..]--crate-type lib --emit=[..]link -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..] -[RUNNING] `[..] rustc --crate-name bar bar/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 [..] +[RUNNING] `[..] rustc --crate-name bar bar/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 -C debuginfo=0[..] [COMPILING] bdep [..] -[RUNNING] `[..] rustc --crate-name bdep bdep/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 [..] +[RUNNING] `[..] rustc --crate-name bdep bdep/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 -C debuginfo=0[..] [COMPILING] foo [..] -[RUNNING] `[..] rustc --crate-name build_script_build build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=5 [..] +[RUNNING] `[..] rustc --crate-name build_script_build build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=5 -C debuginfo=0[..] [RUNNING] `[..]/target/debug/build/foo-[..]/build-script-build` [foo 0.0.1] foo custom build PROFILE=debug DEBUG=true OPT_LEVEL=0 [RUNNING] `[..] rustc --crate-name foo src/lib.rs [..]--crate-type lib --emit=[..]link -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..] @@ -100,9 +100,6 @@ fn profile_selection_build() { [FINISHED] dev [unoptimized + debuginfo] [..] " ) - .with_stderr_line_without(&["[RUNNING] `[..] rustc --crate-name bar bar/src/lib.rs [..]-C codegen-units=5 [..]"], &["-C debuginfo"]) - .with_stderr_line_without(&["[RUNNING] `[..] rustc --crate-name bdep bdep/src/lib.rs [..]-C codegen-units=5 [..]"], &["-C debuginfo"]) - .with_stderr_line_without(&["[RUNNING] `[..] rustc --crate-name build_script_build build.rs [..]-C codegen-units=5 [..]"], &["-C debuginfo"]) .run(); p.cargo("build -vv") .with_stderr_unordered( @@ -158,7 +155,7 @@ fn profile_selection_build_all_targets() { // - Benchmark dependencies are compiled in `dev` mode, which may be // surprising. See issue rust-lang/cargo#4929. // - We make sure that the build dependencies bar, bdep, and build.rs - // are built without debuginfo. + // are built with debuginfo=0. // // - Dependency profiles: // Pkg Target Profile Reason @@ -184,11 +181,11 @@ fn profile_selection_build_all_targets() { [COMPILING] bar [..] [RUNNING] `[..] rustc --crate-name bar bar/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=1 -C debuginfo=2 [..] [RUNNING] `[..] rustc --crate-name bar bar/src/lib.rs [..]--crate-type lib --emit=[..]link -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..] -[RUNNING] `[..] rustc --crate-name bar bar/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 [..] +[RUNNING] `[..] rustc --crate-name bar bar/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 -C debuginfo=0[..] [COMPILING] bdep [..] -[RUNNING] `[..] rustc --crate-name bdep bdep/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 [..] +[RUNNING] `[..] rustc --crate-name bdep bdep/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 -C debuginfo=0[..] [COMPILING] foo [..] -[RUNNING] `[..] rustc --crate-name build_script_build build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=5 [..] +[RUNNING] `[..] rustc --crate-name build_script_build build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=5 -C debuginfo=0[..] [RUNNING] `[..]/target/debug/build/foo-[..]/build-script-build` [foo 0.0.1] foo custom build PROFILE=debug DEBUG=true OPT_LEVEL=0 [RUNNING] `[..] rustc --crate-name foo src/lib.rs [..]--crate-type lib --emit=[..]link -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..]` @@ -202,9 +199,6 @@ fn profile_selection_build_all_targets() { [FINISHED] dev [unoptimized + debuginfo] [..] " ) - .with_stderr_line_without(&["[RUNNING] `[..] rustc --crate-name bar bar/src/lib.rs [..]-C codegen-units=5 [..]"], &["-C debuginfo"]) - .with_stderr_line_without(&["[RUNNING] `[..] rustc --crate-name bdep bdep/src/lib.rs [..]-C codegen-units=5 [..]"], &["-C debuginfo"]) - .with_stderr_line_without(&["[RUNNING] `[..] rustc --crate-name build_script_build build.rs [..]-C codegen-units=5 [..]"], &["-C debuginfo"]) .run(); p.cargo("build -vv") .with_stderr_unordered( diff --git a/src/tools/cargo/tests/testsuite/publish.rs b/src/tools/cargo/tests/testsuite/publish.rs index 00a79fe73..45b7c7da5 100644 --- a/src/tools/cargo/tests/testsuite/publish.rs +++ b/src/tools/cargo/tests/testsuite/publish.rs @@ -25,6 +25,7 @@ const CLEAN_FOO_JSON: &str = r#" "readme": null, "readme_file": null, "repository": "foo", + "rust_version": null, "vers": "0.0.1" } "#; @@ -49,6 +50,7 @@ fn validate_upload_foo() { "readme": null, "readme_file": null, "repository": null, + "rust_version": null, "vers": "0.0.1" } "#, @@ -77,6 +79,7 @@ fn validate_upload_li() { "readme": null, "readme_file": null, "repository": null, + "rust_version": "1.69", "vers": "0.0.1" } "#, @@ -1270,6 +1273,7 @@ You may press ctrl-c [..] "readme": null, "readme_file": null, "repository": null, + "rust_version": null, "vers": "0.0.1" } "#, @@ -1469,6 +1473,7 @@ You may press ctrl-c [..] "readme": null, "readme_file": null, "repository": null, + "rust_version": null, "vers": "0.1.0" } "#, @@ -1581,6 +1586,7 @@ You may press ctrl-c [..] "readme": null, "readme_file": null, "repository": "foo", + "rust_version": null, "vers": "0.1.0" } "#, @@ -1756,6 +1762,9 @@ fn publish_with_missing_readme() { .with_stderr(&format!( "\ [UPDATING] [..] +[WARNING] readme `foo.md` does not appear to exist (relative to `[..]/foo`). +Please update the readme setting in the manifest at `[..]/foo/Cargo.toml` +This may become a hard error in the future. [PACKAGING] foo v0.1.0 [..] [PACKAGED] [..] files, [..] ([..] compressed) [UPLOADING] foo v0.1.0 [..] @@ -2046,6 +2055,7 @@ fn in_package_workspace() { [package] name = "li" version = "0.0.1" + rust-version = "1.69" description = "li" license = "MIT" "#, @@ -2148,6 +2158,7 @@ fn in_package_workspace_with_members_with_features_old() { [package] name = "li" version = "0.0.1" + rust-version = "1.69" description = "li" license = "MIT" "#, @@ -2243,6 +2254,7 @@ fn in_virtual_workspace_with_p() { [package] name = "li" version = "0.0.1" + rust-version = "1.69" description = "li" license = "MIT" "#, diff --git a/src/tools/cargo/tests/testsuite/registry.rs b/src/tools/cargo/tests/testsuite/registry.rs index 05ec9b158..bd5e42b45 100644 --- a/src/tools/cargo/tests/testsuite/registry.rs +++ b/src/tools/cargo/tests/testsuite/registry.rs @@ -2546,7 +2546,7 @@ fn package_lock_inside_package_is_overwritten() { .join("bar-0.0.1") .join(".cargo-ok"); - assert_eq!(ok.metadata().unwrap().len(), 2); + assert_eq!(ok.metadata().unwrap().len(), 7); } #[cargo_test] @@ -2586,7 +2586,7 @@ fn package_lock_as_a_symlink_inside_package_is_overwritten() { let librs = pkg_root.join("src/lib.rs"); // Is correctly overwritten and doesn't affect the file linked to - assert_eq!(ok.metadata().unwrap().len(), 2); + assert_eq!(ok.metadata().unwrap().len(), 7); assert_eq!(fs::read_to_string(librs).unwrap(), "pub fn f() {}"); } @@ -3135,7 +3135,7 @@ fn corrupted_ok_overwritten() { fs::write(&ok, "").unwrap(); assert_eq!(fs::read_to_string(&ok).unwrap(), ""); p.cargo("fetch").with_stderr("").run(); - assert_eq!(fs::read_to_string(&ok).unwrap(), "ok"); + assert_eq!(fs::read_to_string(&ok).unwrap(), r#"{"v":1}"#); } #[cargo_test] @@ -3166,7 +3166,7 @@ fn not_found_permutations() { authors = [] [dependencies] - a-b-c = "1.0" + a-b_c = "1.0" "#, ) .file("src/lib.rs", "") @@ -3177,7 +3177,7 @@ fn not_found_permutations() { .with_stderr( "\ [UPDATING] `dummy-registry` index -error: no matching package named `a-b-c` found +error: no matching package named `a-b_c` found location searched: registry `crates-io` required by package `foo v0.0.1 ([ROOT]/foo)` ", @@ -3190,7 +3190,6 @@ required by package `foo v0.0.1 ([ROOT]/foo)` &[ "/index/a-/b-/a-b-c", "/index/a-/b_/a-b_c", - "/index/a_/b-/a_b-c", "/index/a_/b_/a_b_c" ] ); @@ -3404,3 +3403,129 @@ Caused by: Please slow down ").run(); } + +#[cfg(unix)] +#[cargo_test] +fn set_mask_during_unpacking() { + use std::os::unix::fs::MetadataExt; + + Package::new("bar", "1.0.0") + .file_with_mode("example.sh", 0o777, "#!/bin/sh") + .file_with_mode("src/lib.rs", 0o666, "") + .publish(); + + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = "1.0" + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("fetch") + .with_stderr( + "\ +[UPDATING] `dummy-registry` index +[DOWNLOADING] crates ... +[DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) +", + ) + .run(); + let src_file_path = |path: &str| { + glob::glob( + paths::home() + .join(".cargo/registry/src/*/bar-1.0.0/") + .join(path) + .to_str() + .unwrap(), + ) + .unwrap() + .next() + .unwrap() + .unwrap() + }; + + let umask = cargo::util::get_umask(); + let metadata = fs::metadata(src_file_path("src/lib.rs")).unwrap(); + assert_eq!(metadata.mode() & 0o777, 0o666 & !umask); + let metadata = fs::metadata(src_file_path("example.sh")).unwrap(); + assert_eq!(metadata.mode() & 0o777, 0o777 & !umask); +} + +#[cargo_test] +fn unpack_again_when_cargo_ok_is_unrecognized() { + Package::new("bar", "1.0.0").publish(); + + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = "1.0" + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("fetch") + .with_stderr( + "\ +[UPDATING] `dummy-registry` index +[DOWNLOADING] crates ... +[DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) +", + ) + .run(); + + let src_file_path = |path: &str| { + glob::glob( + paths::home() + .join(".cargo/registry/src/*/bar-1.0.0/") + .join(path) + .to_str() + .unwrap(), + ) + .unwrap() + .next() + .unwrap() + .unwrap() + }; + + // Change permissions to simulate the old behavior not respecting umask. + let lib_rs = src_file_path("src/lib.rs"); + let cargo_ok = src_file_path(".cargo-ok"); + let mut perms = fs::metadata(&lib_rs).unwrap().permissions(); + assert!(!perms.readonly()); + perms.set_readonly(true); + fs::set_permissions(&lib_rs, perms).unwrap(); + let ok = fs::read_to_string(&cargo_ok).unwrap(); + assert_eq!(&ok, r#"{"v":1}"#); + + p.cargo("fetch").with_stderr("").run(); + + // Without changing `.cargo-ok`, a unpack won't be triggered. + let perms = fs::metadata(&lib_rs).unwrap().permissions(); + assert!(perms.readonly()); + + // Write "ok" to simulate the old behavior and trigger the unpack again. + fs::write(&cargo_ok, "ok").unwrap(); + + p.cargo("fetch").with_stderr("").run(); + + // Permission has been restored and `.cargo-ok` is in the new format. + let perms = fs::metadata(lib_rs).unwrap().permissions(); + assert!(!perms.readonly()); + let ok = fs::read_to_string(&cargo_ok).unwrap(); + assert_eq!(&ok, r#"{"v":1}"#); +} diff --git a/src/tools/cargo/tests/testsuite/registry_auth.rs b/src/tools/cargo/tests/testsuite/registry_auth.rs index 7779e285a..97cdf6748 100644 --- a/src/tools/cargo/tests/testsuite/registry_auth.rs +++ b/src/tools/cargo/tests/testsuite/registry_auth.rs @@ -1,6 +1,7 @@ //! Tests for registry authentication. -use cargo_test_support::registry::{Package, RegistryBuilder}; +use cargo_test_support::compare::match_contains; +use cargo_test_support::registry::{Package, RegistryBuilder, Token}; use cargo_test_support::{project, Execs, Project}; fn cargo(p: &Project, s: &str) -> Execs { @@ -517,3 +518,73 @@ Caused by: ) .run(); } + +#[cargo_test] +fn token_not_logged() { + // Checks that the token isn't displayed in debug output (for both HTTP + // index and registry API). Note that this doesn't fully verify the + // correct behavior since we don't have an HTTP2 server, and curl behaves + // significantly differently when using HTTP2. + let crates_io = RegistryBuilder::new() + .http_api() + .http_index() + .auth_required() + .token(Token::Plaintext("a-unique_token".to_string())) + .build(); + Package::new("bar", "1.0.0").publish(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = "1.0" + "#, + ) + .file("src/lib.rs", "") + .build(); + let output = cargo(&p, "publish") + .replace_crates_io(crates_io.index_url()) + .env("CARGO_HTTP_DEBUG", "true") + .env("CARGO_LOG", "trace") + .exec_with_output() + .unwrap(); + let log = String::from_utf8(output.stderr).unwrap(); + let lines = "\ +[UPDATING] crates.io index +[PACKAGING] foo v0.1.0 [..] +[VERIFYING] foo v0.1.0 [..] +[DOWNLOADING] crates ... +[DOWNLOADED] bar v1.0.0 +[COMPILING] bar v1.0.0 +[COMPILING] foo v0.1.0 [..] +[FINISHED] [..] +[PACKAGED] 3 files[..] +[UPLOADING] foo v0.1.0[..] +[UPLOADED] foo v0.1.0 to registry `crates-io` +note: Waiting [..] +"; + for line in lines.lines() { + match_contains(line, &log, None).unwrap(); + } + let authorizations: Vec<_> = log + .lines() + .filter(|line| { + line.contains("http-debug:") && line.to_lowercase().contains("authorization") + }) + .collect(); + assert!(authorizations.iter().all(|line| line.contains("REDACTED"))); + // Total authorizations: + // 1. Initial config.json + // 2. config.json again for verification + // 3. /index/3/b/bar + // 4. /dl/bar/1.0.0/download + // 5. /api/v1/crates/new + // 6. config.json for the "wait for publish" + // 7. /index/3/f/foo for the "wait for publish" + assert_eq!(authorizations.len(), 7); + assert!(!log.contains("a-unique_token")); +} diff --git a/src/tools/cargo/tests/testsuite/rustup.rs b/src/tools/cargo/tests/testsuite/rustup.rs new file mode 100644 index 000000000..aa93f546c --- /dev/null +++ b/src/tools/cargo/tests/testsuite/rustup.rs @@ -0,0 +1,262 @@ +//! Tests for Cargo's behavior under Rustup. + +use cargo_test_support::paths::{home, root, CargoPathExt}; +use cargo_test_support::{cargo_process, process, project}; +use std::env; +use std::env::consts::EXE_EXTENSION; +use std::ffi::OsString; +use std::fs; +use std::path::{Path, PathBuf}; + +/// Helper to generate an executable. +fn make_exe(dest: &Path, name: &str, contents: &str, env: &[(&str, PathBuf)]) -> PathBuf { + let rs_name = format!("{name}.rs"); + fs::write( + root().join(&rs_name), + &format!("fn main() {{ {contents} }}"), + ) + .unwrap(); + let mut pb = process("rustc"); + env.iter().for_each(|(key, value)| { + pb.env(key, value); + }); + pb.arg("--edition=2021") + .arg(root().join(&rs_name)) + .exec() + .unwrap(); + let exe = Path::new(name).with_extension(EXE_EXTENSION); + let output = dest.join(&exe); + fs::rename(root().join(&exe), &output).unwrap(); + output +} + +fn prepend_path(path: &Path) -> OsString { + let mut paths = vec![path.to_path_buf()]; + paths.extend(env::split_paths(&env::var_os("PATH").unwrap_or_default())); + env::join_paths(paths).unwrap() +} + +struct RustupEnvironment { + /// Path for ~/.cargo/bin + cargo_bin: PathBuf, + /// Path for ~/.rustup + rustup_home: PathBuf, + /// Path to the cargo executable in the toolchain directory + /// (~/.rustup/toolchain/test-toolchain/bin/cargo.exe). + cargo_toolchain_exe: PathBuf, +} + +/// Creates an executable which prints a message and then runs the *real* rustc. +fn real_rustc_wrapper(bin_dir: &Path, message: &str) -> PathBuf { + let real_rustc = cargo_util::paths::resolve_executable("rustc".as_ref()).unwrap(); + // The toolchain rustc needs to call the real rustc. In order to do that, + // it needs to restore or clear the RUSTUP environment variables so that + // if rustup is installed, it will call the correct rustc. + let rustup_toolchain_setup = match std::env::var_os("RUSTUP_TOOLCHAIN") { + Some(t) => format!( + ".env(\"RUSTUP_TOOLCHAIN\", \"{}\")", + t.into_string().unwrap() + ), + None => format!(".env_remove(\"RUSTUP_TOOLCHAIN\")"), + }; + let mut env = vec![("CARGO_RUSTUP_TEST_real_rustc", real_rustc)]; + let rustup_home_setup = match std::env::var_os("RUSTUP_HOME") { + Some(h) => { + env.push(("CARGO_RUSTUP_TEST_RUSTUP_HOME", h.into())); + format!(".env(\"RUSTUP_HOME\", env!(\"CARGO_RUSTUP_TEST_RUSTUP_HOME\"))") + } + None => format!(".env_remove(\"RUSTUP_HOME\")"), + }; + make_exe( + bin_dir, + "rustc", + &format!( + r#" + eprintln!("{message}"); + let r = std::process::Command::new(env!("CARGO_RUSTUP_TEST_real_rustc")) + .args(std::env::args_os().skip(1)) + {rustup_toolchain_setup} + {rustup_home_setup} + .status(); + std::process::exit(r.unwrap().code().unwrap_or(2)); + "# + ), + &env, + ) +} + +/// Creates a simulation of a rustup environment with `~/.cargo/bin` and +/// `~/.rustup` directories populated with some executables that simulate +/// rustup. +fn simulated_rustup_environment() -> RustupEnvironment { + // Set up ~/.rustup/toolchains/test-toolchain/bin with a custom rustc and cargo. + let rustup_home = home().join(".rustup"); + let toolchain_bin = rustup_home + .join("toolchains") + .join("test-toolchain") + .join("bin"); + toolchain_bin.mkdir_p(); + let rustc_toolchain_exe = real_rustc_wrapper(&toolchain_bin, "real rustc running"); + let cargo_toolchain_exe = make_exe( + &toolchain_bin, + "cargo", + r#"panic!("cargo toolchain should not be called");"#, + &[], + ); + + // Set up ~/.cargo/bin with a typical set of rustup proxies. + let cargo_bin = home().join(".cargo").join("bin"); + cargo_bin.mkdir_p(); + + let rustc_proxy = make_exe( + &cargo_bin, + "rustc", + &format!( + r#" + match std::env::args().next().unwrap().as_ref() {{ + "rustc" => {{}} + arg => panic!("proxy only supports rustc, got {{arg:?}}"), + }} + eprintln!("rustc proxy running"); + let r = std::process::Command::new(env!("CARGO_RUSTUP_TEST_rustc_toolchain_exe")) + .args(std::env::args_os().skip(1)) + .status(); + std::process::exit(r.unwrap().code().unwrap_or(2)); + "# + ), + &[("CARGO_RUSTUP_TEST_rustc_toolchain_exe", rustc_toolchain_exe)], + ); + fs::hard_link( + &rustc_proxy, + cargo_bin.join("cargo").with_extension(EXE_EXTENSION), + ) + .unwrap(); + fs::hard_link( + &rustc_proxy, + cargo_bin.join("rustup").with_extension(EXE_EXTENSION), + ) + .unwrap(); + + RustupEnvironment { + cargo_bin, + rustup_home, + cargo_toolchain_exe, + } +} + +#[cargo_test] +fn typical_rustup() { + // Test behavior under a typical rustup setup with a normal toolchain. + let RustupEnvironment { + cargo_bin, + rustup_home, + cargo_toolchain_exe, + } = simulated_rustup_environment(); + + // Set up a project and run a normal cargo build. + let p = project().file("src/lib.rs", "").build(); + // The path is modified so that cargo will call `rustc` from + // `~/.cargo/bin/rustc to use our custom rustup proxies. + let path = prepend_path(&cargo_bin); + p.cargo("check") + .env("RUSTUP_TOOLCHAIN", "test-toolchain") + .env("RUSTUP_HOME", &rustup_home) + .env("PATH", &path) + .with_stderr( + "\ +[CHECKING] foo v0.0.1 [..] +real rustc running +[FINISHED] [..] +", + ) + .run(); + + // Do a similar test, but with a toolchain link that does not have cargo + // (which normally would do a fallback to nightly/beta/stable). + cargo_toolchain_exe.rm_rf(); + p.build_dir().rm_rf(); + + p.cargo("check") + .env("RUSTUP_TOOLCHAIN", "test-toolchain") + .env("RUSTUP_HOME", &rustup_home) + .env("PATH", &path) + .with_stderr( + "\ +[CHECKING] foo v0.0.1 [..] +real rustc running +[FINISHED] [..] +", + ) + .run(); +} + +// This doesn't work on Windows because Cargo forces the PATH to contain the +// sysroot_libdir, which is actually `bin`, preventing the test from +// overriding the bin directory. +#[cargo_test(ignore_windows = "PATH can't be overridden on Windows")] +fn custom_calls_other_cargo() { + // Test behavior when a custom subcommand tries to manipulate PATH to use + // a different toolchain. + let RustupEnvironment { + cargo_bin, + rustup_home, + cargo_toolchain_exe: _, + } = simulated_rustup_environment(); + + // Create a directory with a custom toolchain (outside of the rustup universe). + let custom_bin = root().join("custom-bin"); + custom_bin.mkdir_p(); + // `cargo` points to the real cargo. + let cargo_exe = cargo_test_support::cargo_exe(); + fs::hard_link(&cargo_exe, custom_bin.join(cargo_exe.file_name().unwrap())).unwrap(); + // `rustc` executes the real rustc. + real_rustc_wrapper(&custom_bin, "custom toolchain rustc running"); + + // A project that cargo-custom will try to build. + let p = project().file("src/lib.rs", "").build(); + + // Create a custom cargo subcommand. + // This will modify PATH to a custom toolchain and call cargo from that. + make_exe( + &cargo_bin, + "cargo-custom", + r#" + use std::env; + use std::process::Command; + + eprintln!("custom command running"); + + let mut paths = vec![std::path::PathBuf::from(env!("CARGO_RUSTUP_TEST_custom_bin"))]; + paths.extend(env::split_paths(&env::var_os("PATH").unwrap_or_default())); + let path = env::join_paths(paths).unwrap(); + + let status = Command::new("cargo") + .arg("check") + .current_dir(env!("CARGO_RUSTUP_TEST_project_dir")) + .env("PATH", path) + .status() + .unwrap(); + assert!(status.success()); + "#, + &[ + ("CARGO_RUSTUP_TEST_custom_bin", custom_bin), + ("CARGO_RUSTUP_TEST_project_dir", p.root()), + ], + ); + + cargo_process("custom") + // Set these to simulate what would happen when running under rustup. + // We want to make sure that cargo-custom does not try to use the + // rustup proxies. + .env("RUSTUP_TOOLCHAIN", "test-toolchain") + .env("RUSTUP_HOME", &rustup_home) + .with_stderr( + "\ +custom command running +[CHECKING] foo [..] +custom toolchain rustc running +[FINISHED] [..] +", + ) + .run(); +} diff --git a/src/tools/cargo/tests/testsuite/tree.rs b/src/tools/cargo/tests/testsuite/tree.rs index c3c1ca6d3..e2e74c4f9 100644 --- a/src/tools/cargo/tests/testsuite/tree.rs +++ b/src/tools/cargo/tests/testsuite/tree.rs @@ -1086,6 +1086,59 @@ fn duplicates_with_target() { } #[cargo_test] +fn duplicates_with_proc_macro() { + Package::new("dupe-dep", "1.0.0").publish(); + Package::new("dupe-dep", "2.0.0").publish(); + Package::new("proc", "1.0.0") + .proc_macro(true) + .dep("dupe-dep", "1.0") + .publish(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + proc = "1.0" + dupe-dep = "2.0" + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("tree") + .with_stdout( + "\ +foo v0.1.0 ([..]/foo) +├── dupe-dep v2.0.0 +└── proc v1.0.0 (proc-macro) + └── dupe-dep v1.0.0 +", + ) + .run(); + + p.cargo("tree --duplicates") + .with_stdout( + "\ +dupe-dep v1.0.0 +└── proc v1.0.0 (proc-macro) + └── foo v0.1.0 ([..]/foo) + +dupe-dep v2.0.0 +└── foo v0.1.0 ([..]/foo) +", + ) + .run(); + + p.cargo("tree --duplicates --edges no-proc-macro") + .with_stdout("") + .run(); +} + +#[cargo_test] fn charset() { let p = make_simple_proj(); p.cargo("tree --charset ascii") @@ -1540,8 +1593,6 @@ somedep v1.0.0 "\ somedep v1.0.0 └── foo v0.1.0 ([..]/foo) - -somedep v1.0.0 ", ) .run(); diff --git a/src/tools/cargo/tests/testsuite/update.rs b/src/tools/cargo/tests/testsuite/update.rs index 057c8fca4..1d3ee05b7 100644 --- a/src/tools/cargo/tests/testsuite/update.rs +++ b/src/tools/cargo/tests/testsuite/update.rs @@ -633,6 +633,9 @@ fn update_precise_first_run() { "workspace_members": [ "bar 0.0.1 (path+file://[..]/foo)" ], + "workspace_default_members": [ + "bar 0.0.1 (path+file://[..]/foo)" + ], "workspace_root": "[..]/foo", "metadata": null }"#, diff --git a/src/tools/cargo/tests/testsuite/vendor.rs b/src/tools/cargo/tests/testsuite/vendor.rs index 21a1c097c..2b8b090c2 100644 --- a/src/tools/cargo/tests/testsuite/vendor.rs +++ b/src/tools/cargo/tests/testsuite/vendor.rs @@ -1051,10 +1051,11 @@ fn vendor_preserves_permissions() { p.cargo("vendor --respect-source-config").run(); + let umask = cargo::util::get_umask(); let metadata = fs::metadata(p.root().join("vendor/bar/src/lib.rs")).unwrap(); - assert_eq!(metadata.mode() & 0o777, 0o644); + assert_eq!(metadata.mode() & 0o777, 0o644 & !umask); let metadata = fs::metadata(p.root().join("vendor/bar/example.sh")).unwrap(); - assert_eq!(metadata.mode() & 0o777, 0o755); + assert_eq!(metadata.mode() & 0o777, 0o755 & !umask); } #[cargo_test] diff --git a/src/tools/cargo/tests/testsuite/weak_dep_features.rs b/src/tools/cargo/tests/testsuite/weak_dep_features.rs index ee91114df..6f7c03547 100644 --- a/src/tools/cargo/tests/testsuite/weak_dep_features.rs +++ b/src/tools/cargo/tests/testsuite/weak_dep_features.rs @@ -601,6 +601,7 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. "readme": null, "readme_file": null, "repository": null, + "rust_version": null, "vers": "0.1.0" } "#, diff --git a/src/tools/cargo/triagebot.toml b/src/tools/cargo/triagebot.toml index 192859537..00a98e008 100644 --- a/src/tools/cargo/triagebot.toml +++ b/src/tools/cargo/triagebot.toml @@ -9,7 +9,6 @@ allow-unauthenticated = [ "S-*", "Z-*", "beta-nominated", - "needs-mcve", "regression-*", "relnotes", ] @@ -104,7 +103,10 @@ trigger_files = ["src/cargo/sources/directory.rs"] trigger_files = ["src/doc/"] [autolabel."A-environment-variables"] -trigger_files = ["crates/home/"] +trigger_files = [ + "crates/home/", + "src/cargo/util/config/environment.rs", +] [autolabel."A-errors"] trigger_files = ["src/cargo/util/diagnostic_server.rs"] @@ -121,6 +123,19 @@ trigger_files = ["src/cargo/core/compiler/future_incompat.rs"] [autolabel."A-git"] trigger_files = ["src/cargo/sources/git/"] +[autolabel."A-infrastructure"] +trigger_files = [ + ".cargo/", + ".github/", + "build.rs", + "ci/", + "clippy.toml", + "crates/xtask-", + "deny.toml", + "publish.py", + "triagebot.toml", +] + [autolabel."A-interacts-with-crates.io"] trigger_files = ["crates/crates-io/", "src/cargo/ops/registry.rs"] @@ -150,7 +165,7 @@ trigger_files = [ ] [autolabel."A-networking"] -trigger_files = ["src/cargo/util/network.rs"] +trigger_files = ["src/cargo/util/network/"] [autolabel."A-overrides"] trigger_files = ["src/cargo/sources/replaced.rs"] @@ -165,13 +180,13 @@ trigger_files = ["src/cargo/core/compiler/fingerprint/"] trigger_files = ["src/cargo/sources/registry/", "src/cargo/core/registry.rs"] [autolabel."A-registry-authentication"] -trigger_files = ["src/cargo/util/auth.rs", "crates/credential/"] +trigger_files = ["src/cargo/util/auth.rs", "credential/"] [autolabel."A-semver"] trigger_files = [ + "crates/semver-check", "src/cargo/util/semver_ext.rs", "src/cargo/util/to_semver.rs", - "src/doc/semver-check/", ] [autolabel."A-source-replacement"] |