summaryrefslogtreecommitdiffstats
path: root/src/tools/cargo
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
commitdc0db358abe19481e475e10c32149b53370f1a1c (patch)
treeab8ce99c4b255ce46f99ef402c27916055b899ee /src/tools/cargo
parentReleasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff)
downloadrustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz
rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tools/cargo')
-rw-r--r--src/tools/cargo/.github/workflows/main.yml9
-rw-r--r--src/tools/cargo/CHANGELOG.md228
-rw-r--r--src/tools/cargo/Cargo.lock677
-rw-r--r--src/tools/cargo/Cargo.toml21
-rw-r--r--src/tools/cargo/README.md2
-rw-r--r--src/tools/cargo/clippy.toml2
-rw-r--r--src/tools/cargo/crates/cargo-test-support/src/containers.rs4
-rw-r--r--src/tools/cargo/crates/cargo-test-support/src/lib.rs6
-rw-r--r--src/tools/cargo/crates/cargo-test-support/src/paths.rs21
-rw-r--r--src/tools/cargo/crates/cargo-test-support/src/registry.rs2
-rw-r--r--src/tools/cargo/crates/cargo-test-support/src/tools.rs15
-rw-r--r--src/tools/cargo/crates/cargo-util/Cargo.toml2
-rw-r--r--src/tools/cargo/crates/cargo-util/src/paths.rs17
-rw-r--r--src/tools/cargo/crates/resolver-tests/Cargo.toml1
-rw-r--r--src/tools/cargo/crates/resolver-tests/src/lib.rs4
-rw-r--r--src/tools/cargo/crates/resolver-tests/tests/resolve.rs4
-rw-r--r--src/tools/cargo/credential/cargo-credential-1password/README.md7
-rw-r--r--src/tools/cargo/credential/cargo-credential-gnome-secret/README.md7
-rw-r--r--src/tools/cargo/credential/cargo-credential-gnome-secret/build.rs7
-rw-r--r--src/tools/cargo/credential/cargo-credential-gnome-secret/src/libsecret.rs190
-rw-r--r--src/tools/cargo/credential/cargo-credential-gnome-secret/src/main.rs194
-rw-r--r--src/tools/cargo/credential/cargo-credential-macos-keychain/README.md7
-rw-r--r--src/tools/cargo/credential/cargo-credential-wincred/README.md7
-rw-r--r--src/tools/cargo/src/bin/cargo/cli.rs162
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/add.rs13
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/install.rs11
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/mod.rs4
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/run.rs90
-rw-r--r--src/tools/cargo/src/bin/cargo/main.rs6
-rw-r--r--src/tools/cargo/src/cargo/core/compiler/build_config.rs22
-rw-r--r--src/tools/cargo/src/cargo/core/compiler/custom_build.rs59
-rw-r--r--src/tools/cargo/src/cargo/core/compiler/fingerprint/mod.rs5
-rw-r--r--src/tools/cargo/src/cargo/core/compiler/mod.rs208
-rw-r--r--src/tools/cargo/src/cargo/core/compiler/unit_dependencies.rs2
-rw-r--r--src/tools/cargo/src/cargo/core/features.rs166
-rw-r--r--src/tools/cargo/src/cargo/core/manifest.rs6
-rw-r--r--src/tools/cargo/src/cargo/core/package.rs41
-rw-r--r--src/tools/cargo/src/cargo/core/package_id.rs16
-rw-r--r--src/tools/cargo/src/cargo/core/profiles.rs56
-rw-r--r--src/tools/cargo/src/cargo/core/resolver/encode.rs9
-rw-r--r--src/tools/cargo/src/cargo/core/resolver/features.rs3
-rw-r--r--src/tools/cargo/src/cargo/core/resolver/resolve.rs4
-rw-r--r--src/tools/cargo/src/cargo/core/resolver/version_prefs.rs3
-rw-r--r--src/tools/cargo/src/cargo/core/shell.rs2
-rw-r--r--src/tools/cargo/src/cargo/core/source/mod.rs27
-rw-r--r--src/tools/cargo/src/cargo/core/source/source_id.rs10
-rw-r--r--src/tools/cargo/src/cargo/core/summary.rs68
-rw-r--r--src/tools/cargo/src/cargo/core/workspace.rs48
-rw-r--r--src/tools/cargo/src/cargo/lib.rs3
-rw-r--r--src/tools/cargo/src/cargo/ops/cargo_clean.rs7
-rw-r--r--src/tools/cargo/src/cargo/ops/cargo_compile/mod.rs6
-rw-r--r--src/tools/cargo/src/cargo/ops/cargo_fetch.rs3
-rw-r--r--src/tools/cargo/src/cargo/ops/cargo_install.rs4
-rw-r--r--src/tools/cargo/src/cargo/ops/cargo_new.rs13
-rw-r--r--src/tools/cargo/src/cargo/ops/cargo_package.rs11
-rw-r--r--src/tools/cargo/src/cargo/ops/cargo_test.rs13
-rw-r--r--src/tools/cargo/src/cargo/ops/lockfile.rs43
-rw-r--r--src/tools/cargo/src/cargo/ops/mod.rs14
-rw-r--r--src/tools/cargo/src/cargo/ops/registry.rs1227
-rw-r--r--src/tools/cargo/src/cargo/ops/registry/login.rs160
-rw-r--r--src/tools/cargo/src/cargo/ops/registry/logout.rs42
-rw-r--r--src/tools/cargo/src/cargo/ops/registry/mod.rs213
-rw-r--r--src/tools/cargo/src/cargo/ops/registry/owner.rs93
-rw-r--r--src/tools/cargo/src/cargo/ops/registry/publish.rs461
-rw-r--r--src/tools/cargo/src/cargo/ops/registry/search.rs95
-rw-r--r--src/tools/cargo/src/cargo/ops/registry/yank.rs76
-rw-r--r--src/tools/cargo/src/cargo/sources/config.rs4
-rw-r--r--src/tools/cargo/src/cargo/sources/git/known_hosts.rs5
-rw-r--r--src/tools/cargo/src/cargo/sources/git/mod.rs10
-rw-r--r--src/tools/cargo/src/cargo/sources/git/oxide.rs4
-rw-r--r--src/tools/cargo/src/cargo/sources/git/source.rs73
-rw-r--r--src/tools/cargo/src/cargo/sources/git/utils.rs445
-rw-r--r--src/tools/cargo/src/cargo/sources/path.rs2
-rw-r--r--src/tools/cargo/src/cargo/sources/registry/download.rs42
-rw-r--r--src/tools/cargo/src/cargo/sources/registry/http_remote.rs84
-rw-r--r--src/tools/cargo/src/cargo/sources/registry/index.rs533
-rw-r--r--src/tools/cargo/src/cargo/sources/registry/local.rs60
-rw-r--r--src/tools/cargo/src/cargo/sources/registry/mod.rs415
-rw-r--r--src/tools/cargo/src/cargo/sources/registry/remote.rs126
-rw-r--r--src/tools/cargo/src/cargo/util/auth/asymmetric.rs155
-rw-r--r--src/tools/cargo/src/cargo/util/auth/mod.rs (renamed from src/tools/cargo/src/cargo/util/auth.rs)129
-rw-r--r--src/tools/cargo/src/cargo/util/command_prelude.rs61
-rw-r--r--src/tools/cargo/src/cargo/util/config/mod.rs41
-rw-r--r--src/tools/cargo/src/cargo/util/config/target.rs18
-rw-r--r--src/tools/cargo/src/cargo/util/interning.rs10
-rw-r--r--src/tools/cargo/src/cargo/util/network/http.rs216
-rw-r--r--src/tools/cargo/src/cargo/util/network/mod.rs40
-rw-r--r--src/tools/cargo/src/cargo/util/network/retry.rs28
-rw-r--r--src/tools/cargo/src/cargo/util/profile.rs2
-rw-r--r--src/tools/cargo/src/cargo/util/restricted_names.rs24
-rw-r--r--src/tools/cargo/src/cargo/util/toml/embedded.rs895
-rw-r--r--src/tools/cargo/src/cargo/util/toml/mod.rs263
-rw-r--r--src/tools/cargo/src/cargo/util/toml_mut/manifest.rs11
-rw-r--r--src/tools/cargo/src/doc/contrib/src/process/index.md10
-rw-r--r--src/tools/cargo/src/doc/contrib/src/process/working-on-cargo.md2
-rw-r--r--src/tools/cargo/src/doc/man/cargo-install.md4
-rw-r--r--src/tools/cargo/src/doc/man/cargo-test.md13
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-bench.txt1
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-build.txt1
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-check.txt1
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-doc.txt1
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-fix.txt1
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-install.txt6
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-package.txt1
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-publish.txt1
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-run.txt1
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-rustc.txt1
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-rustdoc.txt1
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-test.txt18
-rw-r--r--src/tools/cargo/src/doc/man/includes/options-jobs.md3
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-bench.md3
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-build.md3
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-check.md3
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-doc.md3
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-fix.md3
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-install.md7
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-package.md3
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-publish.md3
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-run.md3
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-rustc.md3
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-rustdoc.md3
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-test.md16
-rw-r--r--src/tools/cargo/src/doc/src/faq.md46
-rw-r--r--src/tools/cargo/src/doc/src/reference/config.md5
-rw-r--r--src/tools/cargo/src/doc/src/reference/environment-variables.md1
-rw-r--r--src/tools/cargo/src/doc/src/reference/registry-index.md10
-rw-r--r--src/tools/cargo/src/doc/src/reference/resolver.md2
-rw-r--r--src/tools/cargo/src/doc/src/reference/specifying-dependencies.md40
-rw-r--r--src/tools/cargo/src/doc/src/reference/unstable.md170
-rw-r--r--src/tools/cargo/src/etc/man/cargo-bench.13
-rw-r--r--src/tools/cargo/src/etc/man/cargo-build.13
-rw-r--r--src/tools/cargo/src/etc/man/cargo-check.13
-rw-r--r--src/tools/cargo/src/etc/man/cargo-doc.13
-rw-r--r--src/tools/cargo/src/etc/man/cargo-fix.13
-rw-r--r--src/tools/cargo/src/etc/man/cargo-install.17
-rw-r--r--src/tools/cargo/src/etc/man/cargo-package.13
-rw-r--r--src/tools/cargo/src/etc/man/cargo-publish.13
-rw-r--r--src/tools/cargo/src/etc/man/cargo-run.13
-rw-r--r--src/tools/cargo/src/etc/man/cargo-rustc.13
-rw-r--r--src/tools/cargo/src/etc/man/cargo-rustdoc.13
-rw-r--r--src/tools/cargo/src/etc/man/cargo-test.116
-rw-r--r--src/tools/cargo/tests/internal.rs107
-rw-r--r--src/tools/cargo/tests/testsuite/bench.rs5
-rw-r--r--src/tools/cargo/tests/testsuite/build.rs24
-rw-r--r--src/tools/cargo/tests/testsuite/build_script.rs7
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/add_basic/mod.rs15
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/add_multiple/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/add_normalized_name_external/mod.rs20
l---------src/tools/cargo/tests/testsuite/cargo_add/add_toolchain/in (renamed from src/tools/cargo/tests/testsuite/cargo_add/invalid_git_external/in)0
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/add_toolchain/mod.rs (renamed from src/tools/cargo/tests/testsuite/cargo_add/invalid_git_external/mod.rs)9
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/add_toolchain/out/Cargo.toml (renamed from src/tools/cargo/tests/testsuite/cargo_add/invalid_git_external/out/Cargo.toml)0
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/add_toolchain/stderr.log2
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/add_toolchain/stdout.log (renamed from src/tools/cargo/tests/testsuite/cargo_add/invalid_git_external/stdout.log)0
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/build/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/build_prefer_existing_version/mod.rs18
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/change_rename_target/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/cyclic_features/mod.rs9
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/default_features/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/deprecated_default_features/mod.rs15
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/deprecated_section/mod.rs15
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/detect_workspace_inherit/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/detect_workspace_inherit_features/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/detect_workspace_inherit_optional/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/dev/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/dev_build_conflict/mod.rs15
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/dev_prefer_existing_version/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/dry_run/mod.rs15
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/mod.rs10
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/features/mod.rs10
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/features_empty/mod.rs10
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/features_multiple_occurrences/mod.rs10
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/features_preserve/mod.rs10
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/features_spaced_values/mod.rs10
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/features_unknown/mod.rs10
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/features_unknown_no_features/mod.rs15
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/git/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/git_branch/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/git_conflicts_namever/mod.rs15
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/git_dev/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/git_inferred_name/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/git_inferred_name_multiple/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/git_multiple_names/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/git_normalized_name/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/git_registry/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/git_rev/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/git_tag/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/infer_prerelease/mod.rs5
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/invalid_arg/mod.rs15
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/invalid_git_external/stderr.log12
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/invalid_git_name/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/invalid_manifest/mod.rs15
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/invalid_name_external/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/invalid_path/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/invalid_path_name/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/invalid_path_self/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/invalid_target_empty/mod.rs15
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/invalid_vers/mod.rs15
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/list_features/mod.rs10
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/list_features_path/mod.rs21
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/list_features_path_no_default/mod.rs21
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/locked_changed/mod.rs15
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/locked_unchanged/mod.rs15
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/lockfile_updated/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/manifest_path_package/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/mod.rs95
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/multiple_conflicts_with_features/mod.rs21
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/multiple_conflicts_with_rename/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/namever/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/no_args/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/no_default_features/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/no_optional/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/offline_empty_cache/mod.rs15
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/optional/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_default_features/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_default_features_with_no_default_features/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_features/mod.rs10
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_git_with_path/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_inherit_features_noop/mod.rs2
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_inherit_noop/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_inherit_optional_noop/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_inline_features/mod.rs21
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_name_dev_noop/mod.rs11
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_name_noop/mod.rs11
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_no_default_features/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_no_default_features_with_default_features/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_no_optional/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_no_optional_with_optional/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_optional/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_optional_with_no_optional/mod.rs21
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_path_noop/mod.rs11
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_path_with_version/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_preserves_inline_table/mod.rs10
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_rename_with_no_rename/mod.rs15
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_rename_with_rename/mod.rs15
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_rename_with_rename_noop/mod.rs15
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_version_with_git/mod.rs15
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_version_with_path/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_with_rename/mod.rs15
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_workspace_dep/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/overwrite_workspace_dep_features/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/path/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/path_dev/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/path_inferred_name/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/path_inferred_name_conflicts_full_feature/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/path_normalized_name/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/in/Cargo.toml21
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/in/src/lib.rs0
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/mod.rs31
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/out/Cargo.toml21
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/stderr.log7
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/stdout.log0
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/preserve_sorted/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/preserve_unsorted/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/quiet/mod.rs10
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/registry/mod.rs19
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/rename/mod.rs15
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/require_weak/mod.rs10
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/sorted_table_with_dotted_item/mod.rs22
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/target/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/target_cfg/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/vers/mod.rs15
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/workspace_name/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/workspace_path/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/workspace_path_dev/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_features.rs1
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/in/Cargo.toml6
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/in/src/lib.rs14
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/mod.rs24
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/out/Cargo.toml6
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/out/crates/foo/Cargo.toml11
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/out/crates/foo/src/main.rs3
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/out/src/lib.rs14
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/stderr.log1
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/stdout.log0
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table.in/Cargo.toml1
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/out/Cargo.toml1
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/out/Cargo.toml1
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/out/Cargo.toml1
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/mod.rs1
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/avoid_empty_tables/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/build/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/dev/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/dry_run/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/gc_patch/mod.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/gc_profile/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/gc_replace/mod.rs17
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/invalid_arg/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/invalid_dep/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/invalid_package/mod.rs18
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/invalid_package_multiple/mod.rs18
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/invalid_section/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/invalid_section_dep/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/invalid_target/mod.rs18
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/invalid_target_dep/mod.rs18
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/mod.rs58
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/multiple_deps/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/multiple_dev/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/no_arg/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/offline/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/optional_feature/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/package/mod.rs18
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/remove_basic/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/target/mod.rs18
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/target_build/mod.rs18
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/target_dev/mod.rs18
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/update_lock_file/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/workspace/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/workspace_non_virtual/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/workspace_preserved/mod.rs16
-rw-r--r--src/tools/cargo/tests/testsuite/config.rs62
-rw-r--r--src/tools/cargo/tests/testsuite/config_include.rs112
-rw-r--r--src/tools/cargo/tests/testsuite/cross_compile.rs2
-rw-r--r--src/tools/cargo/tests/testsuite/custom_target.rs2
-rw-r--r--src/tools/cargo/tests/testsuite/directory.rs8
-rw-r--r--src/tools/cargo/tests/testsuite/doc.rs98
-rw-r--r--src/tools/cargo/tests/testsuite/features.rs99
-rw-r--r--src/tools/cargo/tests/testsuite/features2.rs35
-rw-r--r--src/tools/cargo/tests/testsuite/future_incompat_report.rs2
-rw-r--r--src/tools/cargo/tests/testsuite/git.rs68
-rw-r--r--src/tools/cargo/tests/testsuite/install.rs26
-rw-r--r--src/tools/cargo/tests/testsuite/lockfile_compat.rs78
-rw-r--r--src/tools/cargo/tests/testsuite/main.rs1
-rw-r--r--src/tools/cargo/tests/testsuite/profile_config.rs13
-rw-r--r--src/tools/cargo/tests/testsuite/profile_targets.rs51
-rw-r--r--src/tools/cargo/tests/testsuite/profiles.rs52
-rw-r--r--src/tools/cargo/tests/testsuite/required_features.rs7
-rw-r--r--src/tools/cargo/tests/testsuite/run.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/rustc.rs22
-rw-r--r--src/tools/cargo/tests/testsuite/script.rs1184
-rw-r--r--src/tools/cargo/tests/testsuite/test.rs11
-rw-r--r--src/tools/cargo/triagebot.toml16
336 files changed, 9377 insertions, 4032 deletions
diff --git a/src/tools/cargo/.github/workflows/main.yml b/src/tools/cargo/.github/workflows/main.yml
index c522a19a1..3deae6355 100644
--- a/src/tools/cargo/.github/workflows/main.yml
+++ b/src/tools/cargo/.github/workflows/main.yml
@@ -12,9 +12,6 @@ defaults:
permissions:
contents: read
-env:
- CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
-
jobs:
# Check Code style quickly by running `rustfmt` over all code
rustfmt:
@@ -108,10 +105,6 @@ jobs:
- uses: actions/checkout@v3
- name: Dump Environment
run: ci/dump-environment.sh
- - name: Update Rustup (temporary workaround)
- run: rustup self update
- shell: bash
- if: startsWith(matrix.os, 'windows')
- run: rustup update --no-self-update ${{ matrix.rust }} && rustup default ${{ matrix.rust }}
- run: rustup target add ${{ matrix.other }}
- run: rustup component add rustc-dev llvm-tools-preview rust-docs
@@ -225,6 +218,7 @@ jobs:
name: bors build finished
needs:
- build_std
+ - clippy
- docs
- lockfile
- resolver
@@ -241,6 +235,7 @@ jobs:
name: bors build finished
needs:
- build_std
+ - clippy
- docs
- lockfile
- resolver
diff --git a/src/tools/cargo/CHANGELOG.md b/src/tools/cargo/CHANGELOG.md
index 5cb4d11c5..0784b2638 100644
--- a/src/tools/cargo/CHANGELOG.md
+++ b/src/tools/cargo/CHANGELOG.md
@@ -1,10 +1,104 @@
# Changelog
+## Cargo 1.72 (2023-08-24)
+[64fb38c9...HEAD](https://github.com/rust-lang/cargo/compare/64fb38c9...HEAD)
+
+### Added
+
+- Add support of the "default" keyword to reset previously set `build.jobs`
+ parallelism back to the default.
+ [#12222](https://github.com/rust-lang/cargo/pull/12222)
+
+### Changed
+
+- Cargo now warns when an edition 2021 package is in a virtual workspace and
+ `workspace.resolver` is not set. It is recommended to set the resolver
+ version for workspaces explicitly.
+ [#10910](https://github.com/rust-lang/cargo/pull/10910)
+- Set IBM AIX shared libraries search path to `LIBPATH`.
+ [#11968](https://github.com/rust-lang/cargo/pull/11968)
+- Don't pass `-C debuginfo=0` to rustc as it is the default value.
+ [#12022](https://github.com/rust-lang/cargo/pull/12022)
+ [#12205](https://github.com/rust-lang/cargo/pull/12205)
+- Added a message on reusing previous temporary path on `cargo install` failures.
+ [#12231](https://github.com/rust-lang/cargo/pull/12231)
+- Added a message when `rustup` override shorthand is put in a wrong position.
+ [#12226](https://github.com/rust-lang/cargo/pull/12226)
+
+### Fixed
+
+- `cargo clean` uses `remove_dir_all` as a fallback to resolve race conditions.
+ [#11442](https://github.com/rust-lang/cargo/pull/11442)
+- Reduced the chance Cargo re-formats the user's `[features]` table.
+ [#12191](https://github.com/rust-lang/cargo/pull/12191)
+- Fixed nested Git submodules not able to fetch.
+ [#12244](https://github.com/rust-lang/cargo/pull/12244)
+
+### Nightly only
+
+- 🔥 The `-Zscript` is an experimental feature to add unstable support for
+ single-file packages in Cargo, so we can explore the design and resolve
+ questions with an implementation to collect feedback on.
+ ([eRFC 3424](https://github.com/rust-lang/rfcs/blob/master/text/3424-cargo-script.md))
+ [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#script)
+ [#12245](https://github.com/rust-lang/cargo/pull/12245)
+- Automatically inherit workspace lints when running `cargo new`/`cargo init`.
+ [#12174](https://github.com/rust-lang/cargo/pull/12174)
+
+### Documentation
+
+- Added a description of `Cargo.lock` conflicts in the Cargo FAQ.
+ [#12185](https://github.com/rust-lang/cargo/pull/12185)
+- Added a small note about indexes ignoring SemVer build metadata.
+ [#12206](https://github.com/rust-lang/cargo/pull/12206)
+- Added doc comments for types and friends in `cargo::sources` module.
+ [#12192](https://github.com/rust-lang/cargo/pull/12192)
+ [#12239](https://github.com/rust-lang/cargo/pull/12239)
+ [#12247](https://github.com/rust-lang/cargo/pull/12247)
+
+### Internal
+
+- Updated to `gix` 0.45 for multi-round pack negotiations.
+ [#12236](https://github.com/rust-lang/cargo/pull/12236)
+- Updated to `curl-sys` 0.4.63, which corresponds to curl 8.1.2.
+ [#12218](https://github.com/rust-lang/cargo/pull/12218)
+- Removed unused features from `windows-sys` dependency.
+ [#12176](https://github.com/rust-lang/cargo/pull/12176)
+- Refactored compiler invocations
+ [#12211](https://github.com/rust-lang/cargo/pull/12211)
+- Refactored git and registry sources, and registry data.
+ [#12203](https://github.com/rust-lang/cargo/pull/12203)
+ [#12197](https://github.com/rust-lang/cargo/pull/12197)
+ [#12240](https://github.com/rust-lang/cargo/pull/12240)
+ [#12248](https://github.com/rust-lang/cargo/pull/12248)
+- Lexicographically order `-Z` flags.
+ [#12182](https://github.com/rust-lang/cargo/pull/12182)
+ [#12223](https://github.com/rust-lang/cargo/pull/12223)
+ [#12224](https://github.com/rust-lang/cargo/pull/12224)
+- Several Cargo's own test infra improvements and speed-ups.
+ [#12184](https://github.com/rust-lang/cargo/pull/12184)
+ [#12188](https://github.com/rust-lang/cargo/pull/12188)
+ [#12189](https://github.com/rust-lang/cargo/pull/12189)
+ [#12194](https://github.com/rust-lang/cargo/pull/12194)
+ [#12199](https://github.com/rust-lang/cargo/pull/12199)
+- Migrated print-ban from test to clippy
+ [#12246](https://github.com/rust-lang/cargo/pull/12246)
+
## Cargo 1.71 (2023-07-13)
-[84b7041f...HEAD](https://github.com/rust-lang/cargo/compare/84b7041f...HEAD)
+[84b7041f...rust-1.71.0](https://github.com/rust-lang/cargo/compare/84b7041f...rust-1.71.0)
### Added
+- Allowed named debuginfo options in Cargo.toml.
+ [docs](https://doc.rust-lang.org/nightly/cargo/reference/profiles.html#debug)
+ [#11958](https://github.com/rust-lang/cargo/pull/11958)
+- Added `workspace_default_members` to the output of `cargo metadata`.
+ [#11978](https://github.com/rust-lang/cargo/pull/11978)
+- `cargo add` now considers `rust-version` when selecting packages.
+ [#12078](https://github.com/rust-lang/cargo/pull/12078)
+- Automatically inherit workspace fields when running `cargo new`/`cargo init`.
+ [#12069](https://github.com/rust-lang/cargo/pull/12069)
+
### Changed
- ❗ Optimized the usage under `rustup`. When Cargo detects it will run `rustc`
@@ -23,39 +117,151 @@
[#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)
+- Better error message when empty dependency was specified in Cargo.toml.
+ [#12001](https://github.com/rust-lang/cargo/pull/12001)
+- `--help` text is now wrapping for readability on narrow screens.
+ [#12013](https://github.com/rust-lang/cargo/pull/12013)
+- Tweaked the order of arguments in `--help` text to clarify role of `--bin`.
+ [#12157](https://github.com/rust-lang/cargo/pull/12157)
+- `rust-version` is included in `cargo publish` requests to registries.
+ [#12041](https://github.com/rust-lang/cargo/pull/12041)
### Fixed
- Corrected the bug report URL for `cargo clippy --fix`.
[#11882](https://github.com/rust-lang/cargo/pull/11882)
+- Cargo now applies `[env]` to rust invocations for target info discovery.
+ [#12029](https://github.com/rust-lang/cargo/pull/12029)
+- Fixed tokens not redacted in http debug when using HTTP/2.
+ [#12095](https://github.com/rust-lang/cargo/pull/12095)
+- Fixed `-C debuginfo` not passed in some situation, leading to build cache miss.
+ [#12165](https://github.com/rust-lang/cargo/pull/12165)
+- Fixed the ambiguity when `cargo install` found packages with the same name.
+ The ambiguity happened in a situation like a package depending on old versions
+ of itself.
+ [#12015](https://github.com/rust-lang/cargo/pull/12015)
+- Fixed a false positive that `cargo package` checks for conflict files.
+ [#12135](https://github.com/rust-lang/cargo/pull/12135)
+- Fixed `dep/feat` syntax not working when co-exist with `dep:` syntax, and
+ trying to enable features of an optional dependency.
+ [#12130](https://github.com/rust-lang/cargo/pull/12130)
+- Fixed `cargo tree` not handling the output with `-e no-proc-macro` correctly.
+ [#12044](https://github.com/rust-lang/cargo/pull/12044)
+- Warn instead of error in `cargo package` on empty `readme` or `license-file`
+ in Cargo.toml.
+ [#12036](https://github.com/rust-lang/cargo/pull/12036)
+- Fixed when an HTTP proxy is in use and the Cargo executable links to a
+ certain version of system libcurl, CURL connections might fail. Affected
+ libcurl versions: 7.87.0, 7.88.0, 7.88.1.
+ [#12234](https://github.com/rust-lang/cargo/pull/12234)
+ [#12242](https://github.com/rust-lang/cargo/pull/12242)
### Nightly only
+- 🔥 The `-Zgitoxide` feature now supports shallow clones and fetches for
+ dependencies and registry indexes.
+ [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#gitoxide)
+ [#11840](https://github.com/rust-lang/cargo/pull/11840)
+- 🔥 The `-Zlints` feature enables configuring lints rules in Cargo.toml
+ [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#lints)
+ [#12148](https://github.com/rust-lang/cargo/pull/12148)
+ [#12168](https://github.com/rust-lang/cargo/pull/12168)
- 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)
+- Added `-Zmsrv-policy` feature flag placeholder.
+ [#12043](https://github.com/rust-lang/cargo/pull/12043)
### Documentation
+- Added Cargo team charter.
+ [docs](https://doc.crates.io/contrib/team.html)
+ [#12010](https://github.com/rust-lang/cargo/pull/12010)
+- SemVer: Adding `#[non_exhaustive]` on existing items is a breaking change.
+ [#10877](https://github.com/rust-lang/cargo/pull/10877)
+- SemVer: It is not a breaking change to make an unsafe function safe.
+ [#12116](https://github.com/rust-lang/cargo/pull/12116)
+- SemVer: changeing MSRV is generally a minor change.
+ [#12122](https://github.com/rust-lang/cargo/pull/12122)
+- Clarify when and how to `cargo yank`.
+ [#11862](https://github.com/rust-lang/cargo/pull/11862)
+- Clarify that crates.io doesn't link to docs.rs right away.
+ [#12146](https://github.com/rust-lang/cargo/pull/12146)
+- Clarify documentation around test target setting.
+ [#12032](https://github.com/rust-lang/cargo/pull/12032)
+- Specify `rust_version` in Index format.
+ [#12040](https://github.com/rust-lang/cargo/pull/12040)
+- Specify `msg` in owner-remove registry API response.
+ [#12068](https://github.com/rust-lang/cargo/pull/12068)
+- Added more documentation for artifact-dependencies.
+ [#12110](https://github.com/rust-lang/cargo/pull/12110)
+- Added doc comments for `Source` and build script for cargo-the-library.
+ [#12133](https://github.com/rust-lang/cargo/pull/12133)
+ [#12153](https://github.com/rust-lang/cargo/pull/12153)
+ [#12159](https://github.com/rust-lang/cargo/pull/12159)
+- Several typo and broken link fixes.
+ [#12018](https://github.com/rust-lang/cargo/pull/12018)
+ [#12020](https://github.com/rust-lang/cargo/pull/12020)
+ [#12049](https://github.com/rust-lang/cargo/pull/12049)
+ [#12067](https://github.com/rust-lang/cargo/pull/12067)
+ [#12073](https://github.com/rust-lang/cargo/pull/12073)
+ [#12143](https://github.com/rust-lang/cargo/pull/12143)
+- home: clarify the behavior on each platform
+ [#12047](https://github.com/rust-lang/cargo/pull/12047)
+
### Internal
-- Cargo is now a Cargo workspace. We dogfood ourselves finally.
+- Updated to `linux-raw-sys` 0.3.2
+ [#11998](https://github.com/rust-lang/cargo/pull/11998)
+- Updated to `git2` 0.17.1, which corresponds to libgit2 1.6.4.
+ [#12096](https://github.com/rust-lang/cargo/pull/12096)
+- Updated to `windows-sys` 0.48.0
+ [#12021](https://github.com/rust-lang/cargo/pull/12021)
+- Updated to `libc` 0.2.144
+ [#12014](https://github.com/rust-lang/cargo/pull/12014)
+ [#12098](https://github.com/rust-lang/cargo/pull/12098)
+- Updated to `openssl-src` 111.25.3+1.1.1t
+ [#12005](https://github.com/rust-lang/cargo/pull/12005)
+- Updated to `home` 0.5.5
+ [#12037](https://github.com/rust-lang/cargo/pull/12037)
+- Enabled feature `Win32_System_Console` feature since it is used.
+ [#12016](https://github.com/rust-lang/cargo/pull/12016)
+- 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.
+ [#12024](https://github.com/rust-lang/cargo/pull/12024)
+ [#12025](https://github.com/rust-lang/cargo/pull/12025)
+ [#12057](https://github.com/rust-lang/cargo/pull/12057)
+- 🔥 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)
+- Allow win/mac credential managers to build on all platforms.
+ [#11993](https://github.com/rust-lang/cargo/pull/11993)
+ [#12027](https://github.com/rust-lang/cargo/pull/12027)
+- Use `openssl` only on non-Windows platforms.
+ [#11979](https://github.com/rust-lang/cargo/pull/11979)
+- Use restricted Damerau-Levenshtein algorithm to provide typo suggestions.
+ [#11963](https://github.com/rust-lang/cargo/pull/11963)
+- Added a new xtask `cargo build-man`.
+ [#12048](https://github.com/rust-lang/cargo/pull/12048)
+- Added a new xtask `cargo stale-label`.
+ [#12051](https://github.com/rust-lang/cargo/pull/12051)
+- Added a new xtask `cargo unpublished`.
+ [#12039](https://github.com/rust-lang/cargo/pull/12039)
+ [#12045](https://github.com/rust-lang/cargo/pull/12045)
+ [#12085](https://github.com/rust-lang/cargo/pull/12085)
+- CI: check if any version bump needed for member crates.
+ [#12126](https://github.com/rust-lang/cargo/pull/12126)
+- Fixed some test infra issues.
+ [#11976](https://github.com/rust-lang/cargo/pull/11976)
+ [#12026](https://github.com/rust-lang/cargo/pull/12026)
+ [#12055](https://github.com/rust-lang/cargo/pull/12055)
+ [#12117](https://github.com/rust-lang/cargo/pull/12117)
## Cargo 1.70 (2023-06-01)
[9880b408...rust-1.70.0](https://github.com/rust-lang/cargo/compare/9880b408...rust-1.70.0)
@@ -90,7 +296,7 @@
[#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.
+- Refined `cargo publish` 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.
@@ -392,7 +598,7 @@
for each revision from the same git repository.
[#10690](https://github.com/rust-lang/cargo/pull/1090)
- Cargo contributors can relabel issues via triagebot.
- [doc](https://github.com/rust-lang/triagebot/wiki/Labeling)
+ [doc](https://forge.rust-lang.org/triagebot/labeling.html)
[#11498](https://github.com/rust-lang/cargo/pull/11498)
- Cargo contributors can write tests in containers.
[#11583](https://github.com/rust-lang/cargo/pull/11583)
diff --git a/src/tools/cargo/Cargo.lock b/src/tools/cargo/Cargo.lock
index 14fd1d056..fe365bbcb 100644
--- a/src/tools/cargo/Cargo.lock
+++ b/src/tools/cargo/Cargo.lock
@@ -30,50 +30,68 @@ dependencies = [
]
[[package]]
+name = "aho-corasick"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
name = "anstream"
-version = "0.2.6"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "342258dd14006105c2b75ab1bd7543a03bdf0cfc94383303ac212a04939dff6f"
+checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
dependencies = [
"anstyle",
"anstyle-parse",
+ "anstyle-query",
"anstyle-wincon",
- "concolor-override",
- "concolor-query",
+ "colorchoice",
"is-terminal",
"utf8parse",
]
[[package]]
name = "anstyle"
-version = "0.3.5"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23ea9e81bd02e310c216d080f6223c179012256e5151c41db88d12c88a1684d2"
+checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d"
[[package]]
name = "anstyle-parse"
-version = "0.1.1"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7d1bb534e9efed14f3e5f44e7dd1a4f709384023a4165199a4241e18dff0116"
+checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee"
dependencies = [
"utf8parse",
]
[[package]]
+name = "anstyle-query"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
+dependencies = [
+ "windows-sys 0.48.0",
+]
+
+[[package]]
name = "anstyle-wincon"
-version = "0.2.0"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3127af6145b149f3287bb9a0d10ad9c5692dba8c53ad48285e5bec4063834fa"
+checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
dependencies = [
"anstyle",
- "windows-sys 0.45.0",
+ "windows-sys 0.48.0",
]
[[package]]
name = "anyhow"
-version = "1.0.70"
+version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4"
+checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
[[package]]
name = "arc-swap"
@@ -112,9 +130,9 @@ checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
[[package]]
name = "base64"
-version = "0.21.0"
+version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
+checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
[[package]]
name = "base64ct"
@@ -156,9 +174,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
-version = "2.2.1"
+version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24a6904aef64d73cf10ab17ebace7befb918b82164785cb89907993be7f83813"
+checksum = "6dbe3c979c178231552ecba20214a8272df4e09f232a87aef4320cf06539aded"
[[package]]
name = "bitmaps"
@@ -180,9 +198,9 @@ dependencies = [
[[package]]
name = "bstr"
-version = "1.4.0"
+version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09"
+checksum = "a246e68bb43f6cd9db24bea052a53e40405417c5fb372e3d1a8a7f770a564ef5"
dependencies = [
"memchr",
"once_cell",
@@ -201,9 +219,9 @@ dependencies = [
[[package]]
name = "bumpalo"
-version = "3.12.0"
+version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
+checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
[[package]]
name = "byteorder"
@@ -244,7 +262,7 @@ dependencies = [
[[package]]
name = "cargo"
-version = "0.72.1"
+version = "0.73.0"
dependencies = [
"anyhow",
"base64",
@@ -253,7 +271,7 @@ dependencies = [
"cargo-test-macro",
"cargo-test-support",
"cargo-util",
- "clap 4.2.1",
+ "clap 4.3.3",
"crates-io",
"curl",
"curl-sys",
@@ -274,10 +292,8 @@ dependencies = [
"ignore",
"im-rc",
"indexmap",
- "is-terminal",
"itertools",
"jobserver",
- "lazy_static",
"lazycell",
"libc",
"libgit2-sys",
@@ -289,6 +305,7 @@ dependencies = [
"pasetors",
"pathdiff",
"pretty_env_logger",
+ "pulldown-cmark",
"rand",
"rustfix",
"same-file",
@@ -301,6 +318,7 @@ dependencies = [
"shell-escape",
"snapbox",
"strip-ansi-escapes",
+ "syn 2.0.18",
"tar",
"tempfile",
"termcolor",
@@ -399,7 +417,7 @@ dependencies = [
[[package]]
name = "cargo-util"
-version = "0.2.4"
+version = "0.2.5"
dependencies = [
"anyhow",
"core-foundation",
@@ -464,18 +482,18 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.2.1"
+version = "4.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3"
+checksum = "ca8f255e4b8027970e78db75e78831229c9815fdbfa67eb1a1b777a62e24b4a0"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
-version = "4.2.1"
+version = "4.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "223163f58c9a40c3b0a43e1c4b50a9ce09f007ea2cb1ec258a687945b4b7929f"
+checksum = "acd4f3c17c83b0ba34ffbc4f8bbd74f079413f747f84a6f89292f138057e36ab"
dependencies = [
"anstream",
"anstyle",
@@ -487,9 +505,9 @@ dependencies = [
[[package]]
name = "clap_lex"
-version = "0.4.1"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1"
+checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
[[package]]
name = "clru"
@@ -498,19 +516,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8191fa7302e03607ff0e237d4246cc043ff5b3cb9409d995172ba3bea16b807"
[[package]]
-name = "concolor-override"
+name = "colorchoice"
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",
-]
+checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "const-oid"
@@ -545,9 +554,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
[[package]]
name = "cpufeatures"
-version = "0.2.6"
+version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181"
+checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58"
dependencies = [
"libc",
]
@@ -632,9 +641,9 @@ dependencies = [
[[package]]
name = "crossbeam-epoch"
-version = "0.9.14"
+version = "0.9.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
+checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
dependencies = [
"autocfg",
"cfg-if",
@@ -645,18 +654,18 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
-version = "0.8.15"
+version = "0.8.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
+checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
dependencies = [
"cfg-if",
]
[[package]]
name = "crypto-bigint"
-version = "0.5.1"
+version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c2538c4e68e52548bacb3e83ac549f903d44f011ac9d5abb5e132e67d0808f7"
+checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15"
dependencies = [
"generic-array",
"rand_core",
@@ -676,9 +685,9 @@ dependencies = [
[[package]]
name = "csv"
-version = "1.2.1"
+version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b015497079b9a9d69c02ad25de6c0a6edef051ea6360a327d0bd05802ef64ad"
+checksum = "626ae34994d3d8d668f4269922248239db4ae42d538b14c398b74a52208e8086"
dependencies = [
"csv-core",
"itoa 1.0.6",
@@ -728,9 +737,9 @@ dependencies = [
[[package]]
name = "curl-sys"
-version = "0.4.61+curl-8.0.1"
+version = "0.4.63+curl-8.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14d05c10f541ae6f3bc5b3d923c20001f47db7d5f0b2bc6ad16490133842db79"
+checksum = "aeb0fef7046022a1e2ad67a004978f0e3cacb9e3123dc62ce768f92197b771dc"
dependencies = [
"cc",
"libc",
@@ -744,9 +753,9 @@ dependencies = [
[[package]]
name = "der"
-version = "0.7.3"
+version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82b10af9f9f9f2134a42d3f8aa74658660f2e0234b0eb81bd171df8aa32779ed"
+checksum = "56acb310e15652100da43d130af8d97b509e95af61aab1c5a7939ef24337ee17"
dependencies = [
"const-oid",
"pem-rfc7468",
@@ -761,9 +770,9 @@ checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]]
name = "digest"
-version = "0.10.6"
+version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"const-oid",
@@ -773,21 +782,22 @@ dependencies = [
[[package]]
name = "dunce"
-version = "1.0.3"
+version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bd4b30a6560bbd9b4620f4de34c3f14f60848e58a9b7216801afcb4c7b31c3c"
+checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b"
[[package]]
name = "ecdsa"
-version = "0.16.6"
+version = "0.16.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a48e5d537b8a30c0b023116d981b16334be1485af7ca68db3a2b7024cbc957fd"
+checksum = "0997c976637b606099b9985693efa3581e84e41f5c11ba5255f88711058ad428"
dependencies = [
"der",
"digest",
"elliptic-curve",
"rfc6979",
"signature",
+ "spki",
]
[[package]]
@@ -807,9 +817,9 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
[[package]]
name = "elliptic-curve"
-version = "0.13.4"
+version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75c71eaa367f2e5d556414a8eea812bc62985c879748d6403edabd9cb03f16e7"
+checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b"
dependencies = [
"base16ct",
"crypto-bigint",
@@ -912,9 +922,9 @@ dependencies = [
[[package]]
name = "flate2"
-version = "1.0.25"
+version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
+checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743"
dependencies = [
"crc32fast",
"libz-sys",
@@ -944,9 +954,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "form_urlencoded"
-version = "1.1.0"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
+checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
dependencies = [
"percent-encoding",
]
@@ -974,9 +984,9 @@ dependencies = [
[[package]]
name = "getrandom"
-version = "0.2.9"
+version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
+checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
dependencies = [
"cfg-if",
"js-sys",
@@ -987,9 +997,9 @@ dependencies = [
[[package]]
name = "git2"
-version = "0.17.1"
+version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b7905cdfe33d31a88bb2e8419ddd054451f5432d1da9eaf2ac7804ee1ea12d5"
+checksum = "7b989d6a7ca95a362cf2cfc5ad688b3a467be1f87e480b8dad07fee8c79b0044"
dependencies = [
"bitflags 1.3.2",
"libc",
@@ -1014,12 +1024,13 @@ dependencies = [
[[package]]
name = "gix"
-version = "0.44.1"
+version = "0.45.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6bf41b61f7df395284f7a579c0fa1a7e012c5aede655174d4e91299ef1cac643"
+checksum = "bf2a03ec66ee24d1b2bae3ab718f8d14f141613810cb7ff6756f7db667f1cd82"
dependencies = [
"gix-actor",
"gix-attributes",
+ "gix-commitgraph",
"gix-config",
"gix-credentials",
"gix-date",
@@ -1034,6 +1045,7 @@ dependencies = [
"gix-index",
"gix-lock",
"gix-mailmap",
+ "gix-negotiate",
"gix-object",
"gix-odb",
"gix-pack",
@@ -1062,9 +1074,9 @@ dependencies = [
[[package]]
name = "gix-actor"
-version = "0.20.0"
+version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "848efa0f1210cea8638f95691c82a46f98a74b9e3524f01d4955ebc25a8f84f3"
+checksum = "9fe73f9f6be1afbf1bd5be919a9636fa560e2f14d42262a934423ed6760cd838"
dependencies = [
"bstr",
"btoi",
@@ -1076,9 +1088,9 @@ dependencies = [
[[package]]
name = "gix-attributes"
-version = "0.12.0"
+version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3015baa01ad2122fbcaab7863c857a603eb7b7ec12ac8141207c42c6439805e2"
+checksum = "78b79590ac382f80d87e06416f5fcac6fee5d83dcb152a00ed0bdbaa988acc31"
dependencies = [
"bstr",
"gix-glob",
@@ -1093,36 +1105,50 @@ dependencies = [
[[package]]
name = "gix-bitmap"
-version = "0.2.3"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55a95f4942360766c3880bdb2b4b57f1ef73b190fc424755e7fdf480430af618"
+checksum = "fc02feb20ad313d52a450852f2005c2205d24f851e74d82b7807cbe12c371667"
dependencies = [
"thiserror",
]
[[package]]
name = "gix-chunk"
-version = "0.4.1"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0d39583cab06464b8bf73b3f1707458270f0e7383cb24c3c9c1a16e6f792978"
+checksum = "a7acf3bc6c4b91e8fb260086daf5e105ea3a6d913f5fd3318137f7e309d6e540"
dependencies = [
"thiserror",
]
[[package]]
name = "gix-command"
-version = "0.2.4"
+version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2c6f75c1e0f924de39e750880a6e21307194bb1ab773efe3c7d2d787277f8ab"
+checksum = "5f6141b70cfb21255223e42f3379855037cbbe8673b58dd8318d2f09b516fad1"
dependencies = [
"bstr",
]
[[package]]
+name = "gix-commitgraph"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8490ae1b3d55c47e6a71d247c082304a2f79f8d0332c1a2f5693d42a2021a09"
+dependencies = [
+ "bstr",
+ "gix-chunk",
+ "gix-features",
+ "gix-hash",
+ "memmap2",
+ "thiserror",
+]
+
+[[package]]
name = "gix-config"
-version = "0.22.0"
+version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d252a0eddb6df74600d3d8872dc9fe98835a7da43110411d705b682f49d4ac1"
+checksum = "51f310120ae1ba8f0ca52fb22876ce9bad5b15c8ffb3eb7302e4b64a3b9f681c"
dependencies = [
"bstr",
"gix-config-value",
@@ -1142,11 +1168,11 @@ dependencies = [
[[package]]
name = "gix-config-value"
-version = "0.12.0"
+version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "786861e84a5793ad5f863d846de5eb064cd23b87e61ad708c8c402608202e7be"
+checksum = "6f216df1c33e6e1555923eff0096858a879e8aaadd35b5d788641e4e8064c892"
dependencies = [
- "bitflags 2.2.1",
+ "bitflags 2.3.2",
"bstr",
"gix-path",
"libc",
@@ -1155,9 +1181,9 @@ dependencies = [
[[package]]
name = "gix-credentials"
-version = "0.14.0"
+version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4874a4fc11ffa844a3c2b87a66957bda30a73b577ef1acf15ac34df5745de5ff"
+checksum = "c6f89fea8acd28f5ef8fa5042146f1637afd4d834bc8f13439d8fd1e5aca0d65"
dependencies = [
"bstr",
"gix-command",
@@ -1171,9 +1197,9 @@ dependencies = [
[[package]]
name = "gix-date"
-version = "0.5.0"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99056f37270715f5c7584fd8b46899a2296af9cae92463bf58b8bd1f5a78e553"
+checksum = "bc164145670e9130a60a21670d9b6f0f4f8de04e5dd256c51fa5a0340c625902"
dependencies = [
"bstr",
"itoa 1.0.6",
@@ -1183,9 +1209,9 @@ dependencies = [
[[package]]
name = "gix-diff"
-version = "0.29.0"
+version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "644a0f2768bc42d7a69289ada80c9e15c589caefc6a315d2307202df83ed1186"
+checksum = "9029ad0083cc286a4bd2f5b3bf66bb66398abc26f2731a2824cd5edfc41a0e33"
dependencies = [
"gix-hash",
"gix-object",
@@ -1195,9 +1221,9 @@ dependencies = [
[[package]]
name = "gix-discover"
-version = "0.18.0"
+version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5012710ebdecf6193c6866d6409a3b702a4aa0d78c605bc343590b44ab9962a1"
+checksum = "aba9c6c0d1f2b2efe65581de73de4305004612d49c83773e783202a7ef204f46"
dependencies = [
"bstr",
"dunce",
@@ -1210,9 +1236,9 @@ dependencies = [
[[package]]
name = "gix-features"
-version = "0.29.0"
+version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf69b0f5c701cc3ae22d3204b671907668f6437ca88862d355eaf9bc47a4f897"
+checksum = "3a8c493409bf6060d408eec9bbdd1b12ea351266b50012e2a522f75dfc7b8314"
dependencies = [
"bytes",
"crc32fast",
@@ -1230,20 +1256,20 @@ dependencies = [
[[package]]
name = "gix-fs"
-version = "0.1.1"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b37a1832f691fdc09910bd267f9a2e413737c1f9ec68c6e31f9e802616278a9"
+checksum = "30da8997008adb87f94e15beb7ee229f8a48e97af585a584bfee4a5a1880aab5"
dependencies = [
"gix-features",
]
[[package]]
name = "gix-glob"
-version = "0.7.0"
+version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c07c98204529ac3f24b34754540a852593d2a4c7349008df389240266627a72a"
+checksum = "cd0ade1e80ab1f079703d1824e1daf73009096386aa7fd2f0477f6e4ac0a558e"
dependencies = [
- "bitflags 2.2.1",
+ "bitflags 2.3.2",
"bstr",
"gix-features",
"gix-path",
@@ -1251,9 +1277,9 @@ dependencies = [
[[package]]
name = "gix-hash"
-version = "0.11.1"
+version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "078eec3ac2808cc03f0bddd2704cb661da5c5dc33b41a9d7947b141d499c7c42"
+checksum = "ee181c85d3955f54c4426e6bfaeeada4428692e1a39b8788c2ac7785fc301dd8"
dependencies = [
"hex",
"thiserror",
@@ -1261,9 +1287,9 @@ dependencies = [
[[package]]
name = "gix-hashtable"
-version = "0.2.0"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afebb85691c6a085b114e01a27f4a61364519298c5826cb87a45c304802299bc"
+checksum = "bd259bd0d96e6153e357a8cdaca76c48e103fd34208b6c0ce77b1ad995834bd2"
dependencies = [
"gix-hash",
"hashbrown 0.13.2",
@@ -1272,9 +1298,9 @@ dependencies = [
[[package]]
name = "gix-ignore"
-version = "0.2.0"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba205b6df563e2906768bb22834c82eb46c5fdfcd86ba2c347270bc8309a05b2"
+checksum = "fc6f7f101a0ccce808dbf7008ba131dede94e20257e7bde7a44cbb2f8c775625"
dependencies = [
"bstr",
"gix-glob",
@@ -1284,11 +1310,11 @@ dependencies = [
[[package]]
name = "gix-index"
-version = "0.16.0"
+version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa282756760f79c401d4f4f42588fbb4aa27bbb4b0830f3b4d3480c21a4ac5a7"
+checksum = "616ba958fabfb11263fa042c35690d48a6c7be4e9277e2c7e24ff263b3fe7b82"
dependencies = [
- "bitflags 2.2.1",
+ "bitflags 2.3.2",
"bstr",
"btoi",
"filetime",
@@ -1306,20 +1332,20 @@ dependencies = [
[[package]]
name = "gix-lock"
-version = "5.0.0"
+version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41b80172055c5d8017a48ddac5cc7a95421c00211047db0165c97853c4f05194"
+checksum = "3ec5d5e6f07316d3553aa7425e3ecd935ec29882556021fe1696297a448af8d2"
dependencies = [
- "fastrand",
"gix-tempfile",
+ "gix-utils",
"thiserror",
]
[[package]]
name = "gix-mailmap"
-version = "0.12.0"
+version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8856cec3bdc3610c06970d28b6cb20a0c6621621cf9a8ec48cbd23f2630f362"
+checksum = "4653701922c920e009f1bc4309feaff14882ade017770788f9a150928da3fa6a"
dependencies = [
"bstr",
"gix-actor",
@@ -1327,10 +1353,25 @@ dependencies = [
]
[[package]]
+name = "gix-negotiate"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "945c3ef1e912e44a5f405fc9e924edf42000566a1b257ed52cb1293300f6f08c"
+dependencies = [
+ "bitflags 2.3.2",
+ "gix-commitgraph",
+ "gix-hash",
+ "gix-object",
+ "gix-revision",
+ "smallvec",
+ "thiserror",
+]
+
+[[package]]
name = "gix-object"
-version = "0.29.1"
+version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c9bb30ce0818d37096daa29efe361a4bc6dd0b51a5726598898be7e9a40a01e1"
+checksum = "8926c8f51c44dec3e709cb5dbc93deb9e8d4064c43c9efc54c158dcdfe8446c7"
dependencies = [
"bstr",
"btoi",
@@ -1347,9 +1388,9 @@ dependencies = [
[[package]]
name = "gix-odb"
-version = "0.45.0"
+version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bca2f324aa67672b6d0f2c0fa93f96eb6a7029d260e4c1df5dce3c015f5e5add"
+checksum = "4b234d806278eeac2f907c8b5a105c4ba537230c1a9d9236d822bf0db291f8f3"
dependencies = [
"arc-swap",
"gix-features",
@@ -1365,9 +1406,9 @@ dependencies = [
[[package]]
name = "gix-pack"
-version = "0.35.0"
+version = "0.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "164a515900a83257ae4aa80e741655bee7a2e39113fb535d7a5ac623b445ff20"
+checksum = "7d2a14cb3156037eedb17d6cb7209b7180522b8949b21fd0fe3184c0a1d0af88"
dependencies = [
"clru",
"gix-chunk",
@@ -1387,9 +1428,9 @@ dependencies = [
[[package]]
name = "gix-packetline"
-version = "0.16.0"
+version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51f53abaf1171d2fe99f80ac8ed6645904a1bfd706674749ac112bdd2d4f0777"
+checksum = "74414f89a6b72fa1a530ce8e646faf1a05499c3f4a5c15441d17ae8c978578eb"
dependencies = [
"bstr",
"hex",
@@ -1398,9 +1439,9 @@ dependencies = [
[[package]]
name = "gix-path"
-version = "0.8.0"
+version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fc78f47095a0c15aea0e66103838f0748f4494bf7a9555dfe0f00425400396c"
+checksum = "c1226f2e50adeb4d76c754c1856c06f13a24cad1624801653fbf09b869e5b808"
dependencies = [
"bstr",
"home 0.5.5",
@@ -1410,9 +1451,9 @@ dependencies = [
[[package]]
name = "gix-prompt"
-version = "0.5.0"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "330d11fdf88fff3366c2491efde2f3e454958efe7d5ddf60272e8fb1d944bb01"
+checksum = "e15fe57fa48572b7d3bf465d6a2a0351cd3c55cba74fd5f0b9c23689f9c1a31e"
dependencies = [
"gix-command",
"gix-config-value",
@@ -1423,9 +1464,9 @@ dependencies = [
[[package]]
name = "gix-protocol"
-version = "0.32.0"
+version = "0.33.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "877e49417f1730f4dbc2f7d9a2ab0f8b2f49ef08f97270691403ecde3d961e3a"
+checksum = "92a17058b45c461f0847528c5fb6ee6e76115e026979eb2d2202f98ee94f6c24"
dependencies = [
"bstr",
"btoi",
@@ -1440,9 +1481,9 @@ dependencies = [
[[package]]
name = "gix-quote"
-version = "0.4.3"
+version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a282f5a8d9ee0b09ec47390ac727350c48f2f5c76d803cd8da6b3e7ad56e0bcb"
+checksum = "29d59489bff95b06dcdabe763b7266d3dc0a628cac1ac1caf65a7ca0a43eeae0"
dependencies = [
"bstr",
"btoi",
@@ -1451,9 +1492,9 @@ dependencies = [
[[package]]
name = "gix-ref"
-version = "0.29.0"
+version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8212ecfe41815a2f1b059d82171d6276758cfac5506a5e0f04ad45ef0b1924a"
+checksum = "ebdd999256f4ce8a5eefa89999879c159c263f3493a951d62aa5ce42c0397e1c"
dependencies = [
"gix-actor",
"gix-features",
@@ -1471,9 +1512,9 @@ dependencies = [
[[package]]
name = "gix-refspec"
-version = "0.10.1"
+version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a6ea733820df67e4cd7797deb12727905824d8f5b7c59d943c456d314475892"
+checksum = "72bfd622abc86dd8ad1ec51b9eb77b4f1a766b94e3a1b87cf4a022c5b5570cf4"
dependencies = [
"bstr",
"gix-hash",
@@ -1485,25 +1526,40 @@ dependencies = [
[[package]]
name = "gix-revision"
-version = "0.13.0"
+version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "810f35e9afeccca999d5d348b239f9c162353127d2e13ff3240e31b919e35476"
+checksum = "5044f56cd7a487ce9b034cbe0252ae0b6b47ff56ca3dabd79bc30214d0932cd7"
dependencies = [
"bstr",
"gix-date",
"gix-hash",
"gix-hashtable",
"gix-object",
+ "gix-revwalk",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-revwalk"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc2623ba8747914f151f5e12b65adac576ab459dbed5f50a36c7a3e9cbf2d3ca"
+dependencies = [
+ "gix-commitgraph",
+ "gix-hash",
+ "gix-hashtable",
+ "gix-object",
+ "smallvec",
"thiserror",
]
[[package]]
name = "gix-sec"
-version = "0.8.0"
+version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "794520043d5a024dfeac335c6e520cb616f6963e30dab995892382e998c12897"
+checksum = "b2b7b38b766eb95dcc5350a9c450030b69892c0902fa35f4a6d0809273bd9dae"
dependencies = [
- "bitflags 2.2.1",
+ "bitflags 2.3.2",
"gix-path",
"libc",
"windows",
@@ -1511,10 +1567,11 @@ dependencies = [
[[package]]
name = "gix-tempfile"
-version = "5.0.2"
+version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2ceb30a610e3f5f2d5f9a5114689fde507ba9417705a8cf3429604275b2153c"
+checksum = "b3785cb010e9dc5c446dfbf02bc1119fc17d3a48a27c029efcb3a3c32953eb10"
dependencies = [
+ "gix-fs",
"libc",
"once_cell",
"parking_lot",
@@ -1525,9 +1582,9 @@ dependencies = [
[[package]]
name = "gix-transport"
-version = "0.31.0"
+version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f01c2bf7b989c679695ef635fc7d9e80072e08101be4b53193c8e8b649900102"
+checksum = "64a39ffed9a9078ed700605e064b15d7c6ae50aa65e7faa36ca6919e8081df15"
dependencies = [
"base64",
"bstr",
@@ -1544,9 +1601,9 @@ dependencies = [
[[package]]
name = "gix-traverse"
-version = "0.25.0"
+version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5be1e807f288c33bb005075111886cceb43ed8a167b3182a0f62c186e2a0dd1"
+checksum = "b0842e984cb4bf26339dc559f3a1b8bf8cdb83547799b2b096822a59f87f33d9"
dependencies = [
"gix-hash",
"gix-hashtable",
@@ -1556,9 +1613,9 @@ dependencies = [
[[package]]
name = "gix-url"
-version = "0.18.0"
+version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfc77f89054297cc81491e31f1bab4027e554b5ef742a44bd7035db9a0f78b76"
+checksum = "f1663df25ac42047a2547618d2a6979a26f478073f6306997429235d2cd4c863"
dependencies = [
"bstr",
"gix-features",
@@ -1570,18 +1627,18 @@ dependencies = [
[[package]]
name = "gix-utils"
-version = "0.1.1"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c10b69beac219acb8df673187a1f07dde2d74092f974fb3f9eb385aeb667c909"
+checksum = "dbcfcb150c7ef553d76988467d223254045bdcad0dc6724890f32fbe96415da5"
dependencies = [
"fastrand",
]
[[package]]
name = "gix-validate"
-version = "0.7.4"
+version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7bd629d3680773e1785e585d76fd4295b740b559cad9141517300d99a0c8c049"
+checksum = "57ea5845b506c7728b9d89f4227cc369a5fc5a1d5b26c3add0f0d323413a3a60"
dependencies = [
"bstr",
"thiserror",
@@ -1589,9 +1646,9 @@ dependencies = [
[[package]]
name = "gix-worktree"
-version = "0.17.0"
+version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10bf56a1f5037d84293ea6cece61d9f27c4866b1e13c1c95f37cf56b7da7af25"
+checksum = "d388ad962e8854402734a7387af8790f6bdbc8d05349052dab16ca4a0def50f6"
dependencies = [
"bstr",
"filetime",
@@ -1620,7 +1677,7 @@ version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc"
dependencies = [
- "aho-corasick",
+ "aho-corasick 0.7.20",
"bstr",
"fnv",
"log",
@@ -1761,9 +1818,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "idna"
-version = "0.3.0"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
+checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
dependencies = [
"unicode-bidi",
"unicode-normalization",
@@ -1841,9 +1898,9 @@ dependencies = [
[[package]]
name = "io-lifetimes"
-version = "1.0.10"
+version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
+checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
dependencies = [
"hermit-abi 0.3.1",
"libc",
@@ -1894,9 +1951,9 @@ dependencies = [
[[package]]
name = "js-sys"
-version = "0.3.61"
+version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730"
+checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
dependencies = [
"wasm-bindgen",
]
@@ -1930,15 +1987,15 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
[[package]]
name = "libc"
-version = "0.2.144"
+version = "0.2.146"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
+checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
[[package]]
name = "libgit2-sys"
-version = "0.15.1+1.6.4"
+version = "0.15.2+1.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb4577bde8cdfc7d6a2a4bcb7b049598597de33ffd337276e9c7db6cd4a2cee7"
+checksum = "a80df2e11fb4a61f4ba2ab42dbe7f74468da143f1a75c74e11dee7c813f694fa"
dependencies = [
"cc",
"libc",
@@ -1950,9 +2007,9 @@ dependencies = [
[[package]]
name = "libm"
-version = "0.2.6"
+version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb"
+checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
[[package]]
name = "libnghttp2-sys"
@@ -1980,9 +2037,9 @@ dependencies = [
[[package]]
name = "libz-sys"
-version = "1.1.8"
+version = "1.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf"
+checksum = "56ee889ecc9568871456d42f603d6a0ce59ff328d291063a45cbdf0036baf6db"
dependencies = [
"cc",
"libc",
@@ -1992,15 +2049,15 @@ dependencies = [
[[package]]
name = "linux-raw-sys"
-version = "0.3.4"
+version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "36eb31c1778188ae1e64398743890d0877fef36d11521ac60406b42016e8c2cf"
+checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
[[package]]
name = "lock_api"
-version = "0.4.9"
+version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
+checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
dependencies = [
"autocfg",
"scopeguard",
@@ -2008,12 +2065,9 @@ dependencies = [
[[package]]
name = "log"
-version = "0.4.17"
+version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
-dependencies = [
- "cfg-if",
-]
+checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
[[package]]
name = "maybe-async"
@@ -2056,9 +2110,9 @@ dependencies = [
[[package]]
name = "memoffset"
-version = "0.8.0"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
+checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
dependencies = [
"autocfg",
]
@@ -2071,9 +2125,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
-version = "0.6.2"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
+checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
dependencies = [
"adler",
]
@@ -2134,9 +2188,9 @@ dependencies = [
[[package]]
name = "once_cell"
-version = "1.17.1"
+version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
+checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "oorandom"
@@ -2156,9 +2210,9 @@ dependencies = [
[[package]]
name = "openssl"
-version = "0.10.50"
+version = "0.10.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e30d8bc91859781f0a943411186324d580f2bbeb71b452fe91ae344806af3f1"
+checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d"
dependencies = [
"bitflags 1.3.2",
"cfg-if",
@@ -2177,7 +2231,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.14",
+ "syn 2.0.18",
]
[[package]]
@@ -2188,18 +2242,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-src"
-version = "111.25.3+1.1.1t"
+version = "111.26.0+1.1.1u"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "924757a6a226bf60da5f7dd0311a34d2b52283dd82ddeb103208ddc66362f80c"
+checksum = "efc62c9f12b22b8f5208c23a7200a442b2e5999f8bdf80233852122b5a4f6f37"
dependencies = [
"cc",
]
[[package]]
name = "openssl-sys"
-version = "0.9.85"
+version = "0.9.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d3d193fb1488ad46ffe3aaabc912cc931d02ee8518fe2959aea8ef52718b0c0"
+checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6"
dependencies = [
"cc",
"libc",
@@ -2272,15 +2326,15 @@ dependencies = [
[[package]]
name = "parking_lot_core"
-version = "0.9.7"
+version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
+checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
dependencies = [
"cfg-if",
"libc",
- "redox_syscall 0.2.16",
+ "redox_syscall 0.3.5",
"smallvec",
- "windows-sys 0.45.0",
+ "windows-targets",
]
[[package]]
@@ -2305,9 +2359,9 @@ dependencies = [
[[package]]
name = "pasetors"
-version = "0.6.6"
+version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "824bf633b85dc1dece2eb07161627ba5d90a951597cd5dbf8d85f4d82b7aea69"
+checksum = "ba765699a309908d55950919a3445e9491453e89b2587b1b2abe4143a48894c0"
dependencies = [
"ct-codecs",
"ed25519-compact",
@@ -2341,15 +2395,15 @@ dependencies = [
[[package]]
name = "percent-encoding"
-version = "2.2.0"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
+checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
[[package]]
name = "pest"
-version = "2.5.7"
+version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b1403e8401ad5dedea73c626b99758535b342502f8d1e361f4a2dd952749122"
+checksum = "e68e84bfb01f0507134eac1e9b410a12ba379d064eab48c50ba4ce329a527b70"
dependencies = [
"thiserror",
"ucd-trie",
@@ -2357,9 +2411,9 @@ dependencies = [
[[package]]
name = "pest_derive"
-version = "2.5.7"
+version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be99c4c1d2fc2769b1d00239431d711d08f6efedcecb8b6e30707160aee99c15"
+checksum = "6b79d4c71c865a25a4322296122e3924d30bc8ee0834c8bfc8b95f7f054afbfb"
dependencies = [
"pest",
"pest_generator",
@@ -2367,22 +2421,22 @@ dependencies = [
[[package]]
name = "pest_generator"
-version = "2.5.7"
+version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e56094789873daa36164de2e822b3888c6ae4b4f9da555a1103587658c805b1e"
+checksum = "6c435bf1076437b851ebc8edc3a18442796b30f1728ffea6262d59bbe28b077e"
dependencies = [
"pest",
"pest_meta",
"proc-macro2",
"quote",
- "syn 2.0.14",
+ "syn 2.0.18",
]
[[package]]
name = "pest_meta"
-version = "2.5.7"
+version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6733073c7cff3d8459fda0e42f13a047870242aed8b509fe98000928975f359e"
+checksum = "745a452f8eb71e39ffd8ee32b3c5f51d03845f99786fa9b68db6ff509c505411"
dependencies = [
"once_cell",
"pest",
@@ -2401,9 +2455,9 @@ dependencies = [
[[package]]
name = "pkg-config"
-version = "0.3.26"
+version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
+checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
name = "plotters"
@@ -2463,47 +2517,46 @@ dependencies = [
[[package]]
name = "primeorder"
-version = "0.13.1"
+version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf8d3875361e28f7753baefef104386e7aa47642c93023356d97fdef4003bfb5"
+checksum = "3c2fcef82c0ec6eefcc179b978446c399b3cdf73c392c35604e399eee6df1ee3"
dependencies = [
"elliptic-curve",
]
[[package]]
name = "proc-macro2"
-version = "1.0.64"
+version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da"
+checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406"
dependencies = [
"unicode-ident",
]
[[package]]
name = "prodash"
-version = "23.1.2"
+version = "25.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9516b775656bc3e8985e19cd4b8c0c0de045095074e453d2c0a513b5f978392d"
+checksum = "3236ce1618b6da4c7b618e0143c4d5b5dc190f75f81c49f248221382f7e9e9ae"
dependencies = [
"parking_lot",
]
[[package]]
name = "proptest"
-version = "1.1.0"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29f1b898011ce9595050a68e60f90bad083ff2987a695a42357134c8381fba70"
+checksum = "4e35c06b98bf36aba164cc17cb25f7e232f5c4aeea73baa14b8a9f0d92dbfa65"
dependencies = [
"bit-set",
"bitflags 1.3.2",
"byteorder",
"lazy_static",
"num-traits",
- "quick-error 2.0.1",
"rand",
"rand_chacha",
"rand_xorshift",
- "regex-syntax",
+ "regex-syntax 0.6.29",
"rusty-fork",
"tempfile",
"unarray",
@@ -2511,9 +2564,9 @@ dependencies = [
[[package]]
name = "pulldown-cmark"
-version = "0.9.2"
+version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63"
+checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998"
dependencies = [
"bitflags 1.3.2",
"memchr",
@@ -2534,9 +2587,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
[[package]]
name = "quote"
-version = "1.0.26"
+version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
+checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
dependencies = [
"proc-macro2",
]
@@ -2631,13 +2684,13 @@ dependencies = [
[[package]]
name = "regex"
-version = "1.7.3"
+version = "1.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d"
+checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f"
dependencies = [
- "aho-corasick",
+ "aho-corasick 1.0.2",
"memchr",
- "regex-syntax",
+ "regex-syntax 0.7.2",
]
[[package]]
@@ -2653,12 +2706,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
+name = "regex-syntax"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
+
+[[package]]
name = "resolver-tests"
version = "0.0.0"
dependencies = [
"cargo",
"cargo-util",
- "is-terminal",
"lazy_static",
"proptest",
"varisat",
@@ -2694,9 +2752,9 @@ dependencies = [
[[package]]
name = "rustix"
-version = "0.37.15"
+version = "0.37.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0661814f891c57c930a610266415528da53c4933e6dea5fb350cbfe048a9ece"
+checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0"
dependencies = [
"bitflags 1.3.2",
"errno",
@@ -2764,9 +2822,9 @@ dependencies = [
[[package]]
name = "security-framework"
-version = "2.8.2"
+version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254"
+checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
@@ -2777,9 +2835,9 @@ dependencies = [
[[package]]
name = "security-framework-sys"
-version = "2.8.0"
+version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4"
+checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7"
dependencies = [
"core-foundation-sys",
"libc",
@@ -2803,9 +2861,9 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.160"
+version = "1.0.164"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c"
+checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
dependencies = [
"serde_derive",
]
@@ -2832,13 +2890,13 @@ dependencies = [
[[package]]
name = "serde_derive"
-version = "1.0.160"
+version = "1.0.164"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df"
+checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.14",
+ "syn 2.0.18",
]
[[package]]
@@ -2852,9 +2910,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.95"
+version = "1.0.96"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744"
+checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
dependencies = [
"itoa 1.0.6",
"ryu",
@@ -2863,9 +2921,9 @@ dependencies = [
[[package]]
name = "serde_spanned"
-version = "0.6.1"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4"
+checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d"
dependencies = [
"serde",
]
@@ -2957,9 +3015,9 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "snapbox"
-version = "0.4.10"
+version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9615402f9cff539301119bdf2c2f328739cf2b45c2116666618fb6ac399f75bb"
+checksum = "f6bccd62078347f89a914e3004d94582e13824d4e3d8a816317862884c423835"
dependencies = [
"anstream",
"anstyle",
@@ -2975,9 +3033,9 @@ dependencies = [
[[package]]
name = "snapbox-macros"
-version = "0.3.3"
+version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8e40c667388ed1cb5060f545d0013bf0a23efdfa6c5c3e9ef592de391cd860f"
+checksum = "eaaf09df9f0eeae82be96290918520214530e738a7fe5a351b0f24cf77c0ca31"
dependencies = [
"anstream",
]
@@ -2994,9 +3052,9 @@ dependencies = [
[[package]]
name = "spki"
-version = "0.7.1"
+version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37a5be806ab6f127c3da44b7378837ebf01dadca8510a0e572460216b228bd0e"
+checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a"
dependencies = [
"base64ct",
"der",
@@ -3025,9 +3083,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "subtle"
-version = "2.4.1"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
+checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "syn"
@@ -3042,9 +3100,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.14"
+version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5"
+checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
dependencies = [
"proc-macro2",
"quote",
@@ -3075,15 +3133,16 @@ dependencies = [
[[package]]
name = "tempfile"
-version = "3.5.0"
+version = "3.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998"
+checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6"
dependencies = [
+ "autocfg",
"cfg-if",
"fastrand",
"redox_syscall 0.3.5",
"rustix",
- "windows-sys 0.45.0",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -3131,7 +3190,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.14",
+ "syn 2.0.18",
]
[[package]]
@@ -3146,9 +3205,9 @@ dependencies = [
[[package]]
name = "time"
-version = "0.3.20"
+version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890"
+checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd"
dependencies = [
"itoa 1.0.6",
"libc",
@@ -3160,15 +3219,15 @@ dependencies = [
[[package]]
name = "time-core"
-version = "0.1.0"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
+checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
[[package]]
name = "time-macros"
-version = "0.2.8"
+version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36"
+checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b"
dependencies = [
"time-core",
]
@@ -3200,9 +3259,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "toml"
-version = "0.7.3"
+version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21"
+checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec"
dependencies = [
"serde",
"serde_spanned",
@@ -3212,18 +3271,18 @@ dependencies = [
[[package]]
name = "toml_datetime"
-version = "0.6.1"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622"
+checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
-version = "0.19.8"
+version = "0.19.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13"
+checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739"
dependencies = [
"indexmap",
"serde",
@@ -3273,9 +3332,9 @@ checksum = "98e90c70c9f0d4d1ee6d0a7d04aa06cb9bbd53d8cfbdd62a0269a7c2eb640552"
[[package]]
name = "unicode-ident"
-version = "1.0.8"
+version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
+checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
[[package]]
name = "unicode-normalization"
@@ -3300,9 +3359,9 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]]
name = "url"
-version = "2.3.1"
+version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
+checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb"
dependencies = [
"form_urlencoded",
"idna",
@@ -3462,9 +3521,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
-version = "0.2.84"
+version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
+checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
@@ -3472,24 +3531,24 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
-version = "0.2.84"
+version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
+checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
- "syn 1.0.109",
+ "syn 2.0.18",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.84"
+version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
+checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -3497,28 +3556,28 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.84"
+version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
+checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [
"proc-macro2",
"quote",
- "syn 1.0.109",
+ "syn 2.0.18",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.84"
+version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
+checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
[[package]]
name = "web-sys"
-version = "0.3.61"
+version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97"
+checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -3561,7 +3620,7 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
dependencies = [
- "windows-targets 0.48.0",
+ "windows-targets",
]
[[package]]
@@ -3581,35 +3640,11 @@ dependencies = [
[[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",
+ "windows-targets",
]
[[package]]
@@ -3713,9 +3748,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]]
name = "winnow"
-version = "0.4.1"
+version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28"
+checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699"
dependencies = [
"memchr",
]
@@ -3737,7 +3772,7 @@ version = "0.0.0"
dependencies = [
"anyhow",
"cargo",
- "clap 4.2.1",
+ "clap 4.3.3",
"env_logger 0.10.0",
"log",
]
diff --git a/src/tools/cargo/Cargo.toml b/src/tools/cargo/Cargo.toml
index 05c95c727..7e383be69 100644
--- a/src/tools/cargo/Cargo.toml
+++ b/src/tools/cargo/Cargo.toml
@@ -19,22 +19,22 @@ 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-util = { version = "0.2.5", path = "crates/cargo-util" }
cargo_metadata = "0.14.0"
clap = "4.2.0"
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"
+curl-sys = "0.4.63"
env_logger = "0.10.0"
filetime = "0.2.9"
flate2 = { version = "1.0.3", default-features = false, features = ["zlib"] }
fwdansi = "1.1.0"
git2 = "0.17.1"
git2-curl = "0.18.0"
-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" ] }
+gix = { version = "0.45.1", default-features = false, features = ["blocking-http-transport-curl", "progress-tree"] }
+gix-features-for-configuration-only = { version = "0.30.0", package = "gix-features", features = [ "parallel" ] }
glob = "0.3.0"
handlebars = { version = "3.2.1", features = ["dir_source"] }
hex = "0.4.2"
@@ -45,7 +45,6 @@ humantime = "2.0.0"
ignore = "0.4.7"
im-rc = "15.0.0"
indexmap = "1"
-is-terminal = "0.4.4"
itertools = "0.10.0"
jobserver = "0.1.26"
lazy_static = "1.3.0"
@@ -56,7 +55,7 @@ log = "0.4.17"
memchr = "2.1.3"
miow = "0.5.0"
opener = "0.5"
-openssl ="0.10.50"
+openssl ="0.10.55"
os_info = "3.5.0"
pasetors = { version = "0.6.4", features = ["v3", "paserk", "std", "serde"] }
pathdiff = "0.2"
@@ -80,6 +79,7 @@ sha2 = "0.10.6"
shell-escape = "0.1.4"
snapbox = { version = "0.4.0", features = ["diff", "path"] }
strip-ansi-escapes = "0.1.0"
+syn = { version = "2.0.14", features = ["extra-traits", "full"] }
tar = { version = "0.4.39", default-features = false }
tempfile = "3.1.0"
termcolor = "1.1.2"
@@ -95,7 +95,7 @@ windows-sys = "0.48"
[package]
name = "cargo"
-version = "0.72.1"
+version = "0.73.0"
edition = "2021"
license = "MIT OR Apache-2.0"
homepage = "https://crates.io"
@@ -136,10 +136,8 @@ 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
@@ -150,6 +148,7 @@ os_info.workspace = true
pasetors.workspace = true
pathdiff.workspace = true
pretty_env_logger = { workspace = true, optional = true }
+pulldown-cmark.workspace = true
rand.workspace = true
rustfix.workspace = true
semver.workspace = true
@@ -160,6 +159,7 @@ serde_json = { workspace = true, features = ["raw_value"] }
sha1.workspace = true
shell-escape.workspace = true
strip-ansi-escapes.workspace = true
+syn.workspace = true
tar.workspace = true
tempfile.workspace = true
termcolor.workspace = true
@@ -183,11 +183,8 @@ features = [
"Win32_Foundation",
"Win32_Storage_FileSystem",
"Win32_System_Console",
- "Win32_System_IO",
"Win32_System_Threading",
"Win32_System_JobObjects",
- "Win32_Security",
- "Win32_System_SystemServices"
]
[dev-dependencies]
diff --git a/src/tools/cargo/README.md b/src/tools/cargo/README.md
index 423555e62..1d806b978 100644
--- a/src/tools/cargo/README.md
+++ b/src/tools/cargo/README.md
@@ -13,7 +13,7 @@ Cargo downloads your Rust project’s dependencies and compiles your project.
[![CI](https://github.com/rust-lang/cargo/actions/workflows/main.yml/badge.svg?branch=auto-cargo)](https://github.com/rust-lang/cargo/actions/workflows/main.yml)
-Code documentation: https://docs.rs/cargo/
+Code documentation: <https://doc.rust-lang.org/nightly/nightly-rustc/cargo/>
## Installing Cargo
diff --git a/src/tools/cargo/clippy.toml b/src/tools/cargo/clippy.toml
index 4f9be8f9b..050cc8716 100644
--- a/src/tools/cargo/clippy.toml
+++ b/src/tools/cargo/clippy.toml
@@ -1,3 +1,5 @@
+allow-print-in-tests = true
+allow-dbg-in-tests = true
disallowed-methods = [
{ path = "std::env::var", reason = "Use `Config::get_env` instead. See rust-lang/cargo#11588" },
{ path = "std::env::var_os", reason = "Use `Config::get_env_os` instead. See rust-lang/cargo#11588" },
diff --git a/src/tools/cargo/crates/cargo-test-support/src/containers.rs b/src/tools/cargo/crates/cargo-test-support/src/containers.rs
index 17040d82a..22fd5fd85 100644
--- a/src/tools/cargo/crates/cargo-test-support/src/containers.rs
+++ b/src/tools/cargo/crates/cargo-test-support/src/containers.rs
@@ -94,7 +94,9 @@ impl Container {
let image_base = self.build_context.file_name().unwrap();
let image_name = format!("cargo-test-{}", image_base.to_str().unwrap());
- let _lock = BUILD_LOCK.lock().unwrap();
+ let _lock = BUILD_LOCK
+ .lock()
+ .map_err(|_| panic!("previous docker build failed, unable to run test"));
ProcessBuilder::new("docker")
.args(&["build", "--tag", image_name.as_str()])
.arg(&self.build_context)
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 d27aab44f..a2fa54c60 100644
--- a/src/tools/cargo/crates/cargo-test-support/src/lib.rs
+++ b/src/tools/cargo/crates/cargo-test-support/src/lib.rs
@@ -110,7 +110,9 @@ impl FileBuilder {
fn mk(&mut self) {
if self.executable {
- self.path.set_extension(env::consts::EXE_EXTENSION);
+ let mut path = self.path.clone().into_os_string();
+ write!(path, "{}", env::consts::EXE_SUFFIX).unwrap();
+ self.path = path.into();
}
self.dirname().mkdir_p();
@@ -1259,6 +1261,8 @@ pub trait TestEnv: Sized {
.env("__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS", "stable")
// Keeps cargo within its sandbox.
.env("__CARGO_TEST_DISABLE_GLOBAL_KNOWN_HOST", "1")
+ // Set retry sleep to 1 millisecond.
+ .env("__CARGO_TEST_FIXED_RETRY_SLEEP_MS", "1")
// Incremental generates a huge amount of data per test, which we
// don't particularly need. Tests that specifically need to check
// the incremental behavior should turn this back on.
diff --git a/src/tools/cargo/crates/cargo-test-support/src/paths.rs b/src/tools/cargo/crates/cargo-test-support/src/paths.rs
index ef1fddb70..50040e1d4 100644
--- a/src/tools/cargo/crates/cargo-test-support/src/paths.rs
+++ b/src/tools/cargo/crates/cargo-test-support/src/paths.rs
@@ -1,7 +1,6 @@
use filetime::{self, FileTime};
-use lazy_static::lazy_static;
+
use std::cell::RefCell;
-use std::collections::HashMap;
use std::env;
use std::fs;
use std::io::{self, ErrorKind};
@@ -9,15 +8,11 @@ use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex;
+use std::sync::OnceLock;
static CARGO_INTEGRATION_TEST_DIR: &str = "cit";
-lazy_static! {
- // TODO: Use `SyncOnceCell` when stable
- static ref GLOBAL_ROOT: Mutex<Option<PathBuf>> = Mutex::new(None);
-
- static ref TEST_ROOTS: Mutex<HashMap<String, PathBuf>> = Default::default();
-}
+static GLOBAL_ROOT: OnceLock<Mutex<Option<PathBuf>>> = OnceLock::new();
/// This is used when running cargo is pre-CARGO_TARGET_TMPDIR
/// TODO: Remove when CARGO_TARGET_TMPDIR grows old enough.
@@ -31,7 +26,10 @@ fn global_root_legacy() -> PathBuf {
}
fn set_global_root(tmp_dir: Option<&'static str>) {
- let mut lock = GLOBAL_ROOT.lock().unwrap();
+ let mut lock = GLOBAL_ROOT
+ .get_or_init(|| Default::default())
+ .lock()
+ .unwrap();
if lock.is_none() {
let mut root = match tmp_dir {
Some(tmp_dir) => PathBuf::from(tmp_dir),
@@ -44,7 +42,10 @@ fn set_global_root(tmp_dir: Option<&'static str>) {
}
pub fn global_root() -> PathBuf {
- let lock = GLOBAL_ROOT.lock().unwrap();
+ let lock = GLOBAL_ROOT
+ .get_or_init(|| Default::default())
+ .lock()
+ .unwrap();
match lock.as_ref() {
Some(p) => p.clone(),
None => unreachable!("GLOBAL_ROOT not set yet"),
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 0cf82cb70..910f95bfa 100644
--- a/src/tools/cargo/crates/cargo-test-support/src/registry.rs
+++ b/src/tools/cargo/crates/cargo-test-support/src/registry.rs
@@ -1342,7 +1342,7 @@ impl Package {
/// Sets the index schema version for this package.
///
- /// See `cargo::sources::registry::RegistryPackage` for more information.
+ /// See `cargo::sources::registry::IndexPackage` for more information.
pub fn schema_version(&mut self, version: u32) -> &mut Package {
self.v = Some(version);
self
diff --git a/src/tools/cargo/crates/cargo-test-support/src/tools.rs b/src/tools/cargo/crates/cargo-test-support/src/tools.rs
index 7c056b6fa..2ce2849ae 100644
--- a/src/tools/cargo/crates/cargo-test-support/src/tools.rs
+++ b/src/tools/cargo/crates/cargo-test-support/src/tools.rs
@@ -1,20 +1,21 @@
//! Common executables that can be reused by various tests.
use crate::{basic_manifest, paths, project, Project};
-use lazy_static::lazy_static;
use std::path::{Path, PathBuf};
use std::sync::Mutex;
+use std::sync::OnceLock;
-lazy_static! {
- static ref ECHO_WRAPPER: Mutex<Option<PathBuf>> = Mutex::new(None);
- static ref ECHO: Mutex<Option<PathBuf>> = Mutex::new(None);
-}
+static ECHO_WRAPPER: OnceLock<Mutex<Option<PathBuf>>> = OnceLock::new();
+static ECHO: OnceLock<Mutex<Option<PathBuf>>> = OnceLock::new();
/// Returns the path to an executable that works as a wrapper around rustc.
///
/// The wrapper will echo the command line it was called with to stderr.
pub fn echo_wrapper() -> PathBuf {
- let mut lock = ECHO_WRAPPER.lock().unwrap();
+ let mut lock = ECHO_WRAPPER
+ .get_or_init(|| Default::default())
+ .lock()
+ .unwrap();
if let Some(path) = &*lock {
return path.clone();
}
@@ -53,7 +54,7 @@ pub fn echo_wrapper() -> PathBuf {
///
/// Do not expect this to be anything fancy.
pub fn echo() -> PathBuf {
- let mut lock = ECHO.lock().unwrap();
+ let mut lock = ECHO.get_or_init(|| Default::default()).lock().unwrap();
if let Some(path) = &*lock {
return path.clone();
}
diff --git a/src/tools/cargo/crates/cargo-util/Cargo.toml b/src/tools/cargo/crates/cargo-util/Cargo.toml
index f01705fca..614581037 100644
--- a/src/tools/cargo/crates/cargo-util/Cargo.toml
+++ b/src/tools/cargo/crates/cargo-util/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "cargo-util"
-version = "0.2.4"
+version = "0.2.5"
edition = "2021"
license = "MIT OR Apache-2.0"
homepage = "https://github.com/rust-lang/cargo"
diff --git a/src/tools/cargo/crates/cargo-util/src/paths.rs b/src/tools/cargo/crates/cargo-util/src/paths.rs
index 69df7a209..4a917821b 100644
--- a/src/tools/cargo/crates/cargo-util/src/paths.rs
+++ b/src/tools/cargo/crates/cargo-util/src/paths.rs
@@ -55,6 +55,8 @@ pub fn dylib_path_envvar() -> &'static str {
// penalty starting in 10.13. Cargo's testsuite ran more than twice as
// slow with it on CI.
"DYLD_FALLBACK_LIBRARY_PATH"
+ } else if cfg!(target_os = "aix") {
+ "LIBPATH"
} else {
"LD_LIBRARY_PATH"
}
@@ -411,11 +413,22 @@ fn _create_dir_all(p: &Path) -> Result<()> {
Ok(())
}
-/// Recursively remove all files and directories at the given directory.
+/// Equivalent to [`std::fs::remove_dir_all`] with better error messages.
///
/// This does *not* follow symlinks.
pub fn remove_dir_all<P: AsRef<Path>>(p: P) -> Result<()> {
- _remove_dir_all(p.as_ref())
+ _remove_dir_all(p.as_ref()).or_else(|prev_err| {
+ // `std::fs::remove_dir_all` is highly specialized for different platforms
+ // and may be more reliable than a simple walk. We try the walk first in
+ // order to report more detailed errors.
+ fs::remove_dir_all(p.as_ref()).with_context(|| {
+ format!(
+ "{:?}\n\nError: failed to remove directory `{}`",
+ prev_err,
+ p.as_ref().display(),
+ )
+ })
+ })
}
fn _remove_dir_all(p: &Path) -> Result<()> {
diff --git a/src/tools/cargo/crates/resolver-tests/Cargo.toml b/src/tools/cargo/crates/resolver-tests/Cargo.toml
index 8a7cab113..e0efb9b6d 100644
--- a/src/tools/cargo/crates/resolver-tests/Cargo.toml
+++ b/src/tools/cargo/crates/resolver-tests/Cargo.toml
@@ -7,7 +7,6 @@ publish = false
[dependencies]
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 01d9b5e6d..ab34e8663 100644
--- a/src/tools/cargo/crates/resolver-tests/src/lib.rs
+++ b/src/tools/cargo/crates/resolver-tests/src/lib.rs
@@ -179,7 +179,6 @@ pub fn resolve_with_config_raw(
used: HashSet::new(),
};
let summary = Summary::new(
- config,
pkg_id("root"),
deps,
&BTreeMap::new(),
@@ -581,7 +580,6 @@ pub fn pkg_dep<T: ToPkgId>(name: T, dep: Vec<Dependency>) -> Summary {
None
};
Summary::new(
- &Config::default().unwrap(),
name.to_pkgid(),
dep,
&BTreeMap::new(),
@@ -610,7 +608,6 @@ pub fn pkg_loc(name: &str, loc: &str) -> Summary {
None
};
Summary::new(
- &Config::default().unwrap(),
pkg_id_loc(name, loc),
Vec::new(),
&BTreeMap::new(),
@@ -625,7 +622,6 @@ pub fn remove_dep(sum: &Summary, ind: usize) -> Summary {
deps.remove(ind);
// note: more things will need to be copied over in the future, but it works for now.
Summary::new(
- &Config::default().unwrap(),
sum.package_id(),
deps,
&BTreeMap::new(),
diff --git a/src/tools/cargo/crates/resolver-tests/tests/resolve.rs b/src/tools/cargo/crates/resolver-tests/tests/resolve.rs
index df74826f0..02486bfb5 100644
--- a/src/tools/cargo/crates/resolver-tests/tests/resolve.rs
+++ b/src/tools/cargo/crates/resolver-tests/tests/resolve.rs
@@ -1,3 +1,5 @@
+use std::io::IsTerminal;
+
use cargo::core::dependency::DepKind;
use cargo::core::Dependency;
use cargo::util::Config;
@@ -21,7 +23,7 @@ use proptest::prelude::*;
proptest! {
#![proptest_config(ProptestConfig {
max_shrink_iters:
- if is_ci() || !is_terminal::IsTerminal::is_terminal(&std::io::stderr()){
+ if is_ci() || !std::io::stderr().is_terminal() {
// This attempts to make sure that CI will fail fast,
0
} else {
diff --git a/src/tools/cargo/credential/cargo-credential-1password/README.md b/src/tools/cargo/credential/cargo-credential-1password/README.md
new file mode 100644
index 000000000..7cc15e05b
--- /dev/null
+++ b/src/tools/cargo/credential/cargo-credential-1password/README.md
@@ -0,0 +1,7 @@
+# cargo-credential-1password
+
+This is the implementation for the Cargo credential helper for [1password].
+See the [credential-process] documentation for how to use this.
+
+[1password]: https://1password.com/
+[credential-process]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process
diff --git a/src/tools/cargo/credential/cargo-credential-gnome-secret/README.md b/src/tools/cargo/credential/cargo-credential-gnome-secret/README.md
new file mode 100644
index 000000000..7a4b02838
--- /dev/null
+++ b/src/tools/cargo/credential/cargo-credential-gnome-secret/README.md
@@ -0,0 +1,7 @@
+# cargo-credential-gnome-secret
+
+This is the implementation for the Cargo credential helper for [GNOME libsecret].
+See the [credential-process] documentation for how to use this.
+
+[GNOME libsecret]: https://wiki.gnome.org/Projects/Libsecret
+[credential-process]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process
diff --git a/src/tools/cargo/credential/cargo-credential-gnome-secret/build.rs b/src/tools/cargo/credential/cargo-credential-gnome-secret/build.rs
index 9283535af..8bb86ee43 100644
--- a/src/tools/cargo/credential/cargo-credential-gnome-secret/build.rs
+++ b/src/tools/cargo/credential/cargo-credential-gnome-secret/build.rs
@@ -1,3 +1,8 @@
fn main() {
- pkg_config::probe_library("libsecret-1").unwrap();
+ if cfg!(target_os = "linux") {
+ // TODO: Consider ignoring errors when libsecret is not installed and
+ // switching the impl to UnsupportedCredential (possibly along with a
+ // warning?).
+ pkg_config::probe_library("libsecret-1").unwrap();
+ }
}
diff --git a/src/tools/cargo/credential/cargo-credential-gnome-secret/src/libsecret.rs b/src/tools/cargo/credential/cargo-credential-gnome-secret/src/libsecret.rs
new file mode 100644
index 000000000..c584eeecf
--- /dev/null
+++ b/src/tools/cargo/credential/cargo-credential-gnome-secret/src/libsecret.rs
@@ -0,0 +1,190 @@
+//! Implementation of the libsecret credential helper.
+
+use cargo_credential::{Credential, Error};
+use std::ffi::{CStr, CString};
+use std::os::raw::{c_char, c_int};
+use std::ptr::{null, null_mut};
+
+#[allow(non_camel_case_types)]
+type gchar = c_char;
+
+#[allow(non_camel_case_types)]
+type gboolean = c_int;
+
+type GQuark = u32;
+
+#[repr(C)]
+struct GError {
+ domain: GQuark,
+ code: c_int,
+ message: *mut gchar,
+}
+
+#[repr(C)]
+struct GCancellable {
+ _private: [u8; 0],
+}
+
+#[repr(C)]
+struct SecretSchema {
+ name: *const gchar,
+ flags: SecretSchemaFlags,
+ attributes: [SecretSchemaAttribute; 32],
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct SecretSchemaAttribute {
+ name: *const gchar,
+ attr_type: SecretSchemaAttributeType,
+}
+
+#[repr(C)]
+enum SecretSchemaFlags {
+ None = 0,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+enum SecretSchemaAttributeType {
+ String = 0,
+}
+
+extern "C" {
+ fn secret_password_store_sync(
+ schema: *const SecretSchema,
+ collection: *const gchar,
+ label: *const gchar,
+ password: *const gchar,
+ cancellable: *mut GCancellable,
+ error: *mut *mut GError,
+ ...
+ ) -> gboolean;
+ fn secret_password_clear_sync(
+ schema: *const SecretSchema,
+ cancellable: *mut GCancellable,
+ error: *mut *mut GError,
+ ...
+ ) -> gboolean;
+ fn secret_password_lookup_sync(
+ schema: *const SecretSchema,
+ cancellable: *mut GCancellable,
+ error: *mut *mut GError,
+ ...
+ ) -> *mut gchar;
+}
+
+pub struct GnomeSecret;
+
+fn label(index_url: &str) -> CString {
+ CString::new(format!("cargo-registry:{}", index_url)).unwrap()
+}
+
+fn schema() -> SecretSchema {
+ let mut attributes = [SecretSchemaAttribute {
+ name: null(),
+ attr_type: SecretSchemaAttributeType::String,
+ }; 32];
+ attributes[0] = SecretSchemaAttribute {
+ name: b"url\0".as_ptr() as *const gchar,
+ attr_type: SecretSchemaAttributeType::String,
+ };
+ SecretSchema {
+ name: b"org.rust-lang.cargo.registry\0".as_ptr() as *const gchar,
+ flags: SecretSchemaFlags::None,
+ attributes,
+ }
+}
+
+impl Credential for GnomeSecret {
+ fn name(&self) -> &'static str {
+ env!("CARGO_PKG_NAME")
+ }
+
+ fn get(&self, index_url: &str) -> Result<String, Error> {
+ let mut error: *mut GError = null_mut();
+ let attr_url = CString::new("url").unwrap();
+ let index_url_c = CString::new(index_url).unwrap();
+ let schema = schema();
+ unsafe {
+ let token_c = secret_password_lookup_sync(
+ &schema,
+ null_mut(),
+ &mut error,
+ attr_url.as_ptr(),
+ index_url_c.as_ptr(),
+ null() as *const gchar,
+ );
+ if !error.is_null() {
+ return Err(format!(
+ "failed to get token: {}",
+ CStr::from_ptr((*error).message).to_str()?
+ )
+ .into());
+ }
+ if token_c.is_null() {
+ return Err(format!("cannot find token for {}", index_url).into());
+ }
+ let token = CStr::from_ptr(token_c)
+ .to_str()
+ .map_err(|e| format!("expected utf8 token: {}", e))?
+ .to_string();
+ Ok(token)
+ }
+ }
+
+ fn store(&self, index_url: &str, token: &str, name: Option<&str>) -> Result<(), Error> {
+ let label = label(name.unwrap_or(index_url));
+ let token = CString::new(token).unwrap();
+ let mut error: *mut GError = null_mut();
+ let attr_url = CString::new("url").unwrap();
+ let index_url_c = CString::new(index_url).unwrap();
+ let schema = schema();
+ unsafe {
+ secret_password_store_sync(
+ &schema,
+ b"default\0".as_ptr() as *const gchar,
+ label.as_ptr(),
+ token.as_ptr(),
+ null_mut(),
+ &mut error,
+ attr_url.as_ptr(),
+ index_url_c.as_ptr(),
+ null() as *const gchar,
+ );
+ if !error.is_null() {
+ return Err(format!(
+ "failed to store token: {}",
+ CStr::from_ptr((*error).message).to_str()?
+ )
+ .into());
+ }
+ }
+ Ok(())
+ }
+
+ fn erase(&self, index_url: &str) -> Result<(), Error> {
+ let schema = schema();
+ let mut error: *mut GError = null_mut();
+ let attr_url = CString::new("url").unwrap();
+ let index_url_c = CString::new(index_url).unwrap();
+ unsafe {
+ secret_password_clear_sync(
+ &schema,
+ null_mut(),
+ &mut error,
+ attr_url.as_ptr(),
+ index_url_c.as_ptr(),
+ null() as *const gchar,
+ );
+ if !error.is_null() {
+ return Err(format!(
+ "failed to erase token: {}",
+ CStr::from_ptr((*error).message).to_str()?
+ )
+ .into());
+ }
+ }
+ Ok(())
+ }
+}
diff --git a/src/tools/cargo/credential/cargo-credential-gnome-secret/src/main.rs b/src/tools/cargo/credential/cargo-credential-gnome-secret/src/main.rs
index 40972b05d..1d2ecc61f 100644
--- a/src/tools/cargo/credential/cargo-credential-gnome-secret/src/main.rs
+++ b/src/tools/cargo/credential/cargo-credential-gnome-secret/src/main.rs
@@ -1,193 +1,11 @@
//! Cargo registry gnome libsecret credential process.
-use cargo_credential::{Credential, Error};
-use std::ffi::{CStr, CString};
-use std::os::raw::{c_char, c_int};
-use std::ptr::{null, null_mut};
-
-#[allow(non_camel_case_types)]
-type gchar = c_char;
-
-#[allow(non_camel_case_types)]
-type gboolean = c_int;
-
-type GQuark = u32;
-
-#[repr(C)]
-struct GError {
- domain: GQuark,
- code: c_int,
- message: *mut gchar,
-}
-
-#[repr(C)]
-struct GCancellable {
- _private: [u8; 0],
-}
-
-#[repr(C)]
-struct SecretSchema {
- name: *const gchar,
- flags: SecretSchemaFlags,
- attributes: [SecretSchemaAttribute; 32],
-}
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-struct SecretSchemaAttribute {
- name: *const gchar,
- attr_type: SecretSchemaAttributeType,
-}
-
-#[repr(C)]
-enum SecretSchemaFlags {
- None = 0,
-}
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-enum SecretSchemaAttributeType {
- String = 0,
-}
-
-extern "C" {
- fn secret_password_store_sync(
- schema: *const SecretSchema,
- collection: *const gchar,
- label: *const gchar,
- password: *const gchar,
- cancellable: *mut GCancellable,
- error: *mut *mut GError,
- ...
- ) -> gboolean;
- fn secret_password_clear_sync(
- schema: *const SecretSchema,
- cancellable: *mut GCancellable,
- error: *mut *mut GError,
- ...
- ) -> gboolean;
- fn secret_password_lookup_sync(
- schema: *const SecretSchema,
- cancellable: *mut GCancellable,
- error: *mut *mut GError,
- ...
- ) -> *mut gchar;
-}
-
-struct GnomeSecret;
-
-fn label(index_url: &str) -> CString {
- CString::new(format!("cargo-registry:{}", index_url)).unwrap()
-}
-
-fn schema() -> SecretSchema {
- let mut attributes = [SecretSchemaAttribute {
- name: null(),
- attr_type: SecretSchemaAttributeType::String,
- }; 32];
- attributes[0] = SecretSchemaAttribute {
- name: b"url\0".as_ptr() as *const gchar,
- attr_type: SecretSchemaAttributeType::String,
- };
- SecretSchema {
- name: b"org.rust-lang.cargo.registry\0".as_ptr() as *const gchar,
- flags: SecretSchemaFlags::None,
- attributes,
- }
-}
-
-impl Credential for GnomeSecret {
- fn name(&self) -> &'static str {
- env!("CARGO_PKG_NAME")
- }
-
- fn get(&self, index_url: &str) -> Result<String, Error> {
- let mut error: *mut GError = null_mut();
- let attr_url = CString::new("url").unwrap();
- let index_url_c = CString::new(index_url).unwrap();
- let schema = schema();
- unsafe {
- let token_c = secret_password_lookup_sync(
- &schema,
- null_mut(),
- &mut error,
- attr_url.as_ptr(),
- index_url_c.as_ptr(),
- null() as *const gchar,
- );
- if !error.is_null() {
- return Err(format!(
- "failed to get token: {}",
- CStr::from_ptr((*error).message).to_str()?
- )
- .into());
- }
- if token_c.is_null() {
- return Err(format!("cannot find token for {}", index_url).into());
- }
- let token = CStr::from_ptr(token_c)
- .to_str()
- .map_err(|e| format!("expected utf8 token: {}", e))?
- .to_string();
- Ok(token)
- }
- }
-
- fn store(&self, index_url: &str, token: &str, name: Option<&str>) -> Result<(), Error> {
- let label = label(name.unwrap_or(index_url));
- let token = CString::new(token).unwrap();
- let mut error: *mut GError = null_mut();
- let attr_url = CString::new("url").unwrap();
- let index_url_c = CString::new(index_url).unwrap();
- let schema = schema();
- unsafe {
- secret_password_store_sync(
- &schema,
- b"default\0".as_ptr() as *const gchar,
- label.as_ptr(),
- token.as_ptr(),
- null_mut(),
- &mut error,
- attr_url.as_ptr(),
- index_url_c.as_ptr(),
- null() as *const gchar,
- );
- if !error.is_null() {
- return Err(format!(
- "failed to store token: {}",
- CStr::from_ptr((*error).message).to_str()?
- )
- .into());
- }
- }
- Ok(())
- }
-
- fn erase(&self, index_url: &str) -> Result<(), Error> {
- let schema = schema();
- let mut error: *mut GError = null_mut();
- let attr_url = CString::new("url").unwrap();
- let index_url_c = CString::new(index_url).unwrap();
- unsafe {
- secret_password_clear_sync(
- &schema,
- null_mut(),
- &mut error,
- attr_url.as_ptr(),
- index_url_c.as_ptr(),
- null() as *const gchar,
- );
- if !error.is_null() {
- return Err(format!(
- "failed to erase token: {}",
- CStr::from_ptr((*error).message).to_str()?
- )
- .into());
- }
- }
- Ok(())
- }
-}
+#[cfg(target_os = "linux")]
+mod libsecret;
+#[cfg(not(target_os = "linux"))]
+use cargo_credential::UnsupportedCredential as GnomeSecret;
+#[cfg(target_os = "linux")]
+use libsecret::GnomeSecret;
fn main() {
cargo_credential::main(GnomeSecret);
diff --git a/src/tools/cargo/credential/cargo-credential-macos-keychain/README.md b/src/tools/cargo/credential/cargo-credential-macos-keychain/README.md
new file mode 100644
index 000000000..554116b55
--- /dev/null
+++ b/src/tools/cargo/credential/cargo-credential-macos-keychain/README.md
@@ -0,0 +1,7 @@
+# cargo-credential-macos-keychain
+
+This is the implementation for the Cargo credential helper for [macOS Keychain].
+See the [credential-process] documentation for how to use this.
+
+[macOS Keychain]: https://support.apple.com/guide/keychain-access/welcome/mac
+[credential-process]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process
diff --git a/src/tools/cargo/credential/cargo-credential-wincred/README.md b/src/tools/cargo/credential/cargo-credential-wincred/README.md
new file mode 100644
index 000000000..8c8d18789
--- /dev/null
+++ b/src/tools/cargo/credential/cargo-credential-wincred/README.md
@@ -0,0 +1,7 @@
+# cargo-credential-wincred
+
+This is the implementation for the Cargo credential helper for [Windows Credential Manager].
+See the [credential-process] documentation for how to use this.
+
+[Windows Credential Manager]: https://support.microsoft.com/en-us/windows/accessing-credential-manager-1b5c916a-6a16-889f-8581-fc16e8165ac0
+[credential-process]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process
diff --git a/src/tools/cargo/src/bin/cargo/cli.rs b/src/tools/cargo/src/bin/cargo/cli.rs
index 946816571..db52bc8f2 100644
--- a/src/tools/cargo/src/bin/cargo/cli.rs
+++ b/src/tools/cargo/src/bin/cargo/cli.rs
@@ -1,7 +1,7 @@
use anyhow::{anyhow, Context as _};
use cargo::core::shell::Shell;
use cargo::core::{features, CliUnstable};
-use cargo::{self, drop_print, drop_println, CliResult, Config};
+use cargo::{self, drop_print, drop_println, CargoResult, CliResult, Config};
use clap::{Arg, ArgMatches};
use itertools::Itertools;
use std::collections::HashMap;
@@ -14,16 +14,6 @@ use super::list_commands;
use crate::command_prelude::*;
use cargo::core::features::HIDDEN;
-lazy_static::lazy_static! {
- // Maps from commonly known external commands (not builtin to cargo) to their
- // description, for the help page. Reserved for external subcommands that are
- // core within the rust ecosystem (esp ones that might become internal in the future).
- static ref KNOWN_EXTERNAL_COMMAND_DESCRIPTIONS: HashMap<&'static str, &'static str> = HashMap::from([
- ("clippy", "Checks a package to catch common mistakes and improve your Rust code."),
- ("fmt", "Formats all bin and lib files of the current crate using rustfmt."),
- ]);
-}
-
pub fn main(config: &mut LazyConfig) -> CliResult {
let args = cli().try_get_matches()?;
@@ -128,15 +118,28 @@ Run with 'cargo -Z [FLAG] [COMMAND]'",
}
if expanded_args.flag("list") {
+ // Maps from commonly known external commands (not builtin to cargo)
+ // to their description, for the help page. Reserved for external
+ // subcommands that are core within the rust ecosystem (esp ones that
+ // might become internal in the future).
+ let known_external_command_descriptions = HashMap::from([
+ (
+ "clippy",
+ "Checks a package to catch common mistakes and improve your Rust code.",
+ ),
+ (
+ "fmt",
+ "Formats all bin and lib files of the current crate using rustfmt.",
+ ),
+ ]);
drop_println!(config, "Installed Commands:");
for (name, command) in list_commands(config) {
- let known_external_desc = KNOWN_EXTERNAL_COMMAND_DESCRIPTIONS.get(name.as_str());
+ let known_external_desc = known_external_command_descriptions.get(name.as_str());
match command {
CommandInfo::BuiltIn { about } => {
assert!(
known_external_desc.is_none(),
- "KNOWN_EXTERNAL_COMMANDS shouldn't contain builtin \"{}\"",
- name
+ "known_external_commands shouldn't contain builtin `{name}`",
);
let summary = about.unwrap_or_default();
let summary = summary.lines().next().unwrap_or(&summary); // display only the first line
@@ -172,10 +175,11 @@ Run with 'cargo -Z [FLAG] [COMMAND]'",
return Ok(());
}
};
- config_configure(config, &expanded_args, subcommand_args, global_args)?;
+ let exec = Exec::infer(cmd)?;
+ config_configure(config, &expanded_args, subcommand_args, global_args, &exec)?;
super::init_git(config);
- execute_subcommand(config, cmd, subcommand_args)
+ exec.exec(config, subcommand_args)
}
pub fn get_version_string(is_verbose: bool) -> String {
@@ -255,7 +259,7 @@ fn expand_aliases(
args: ArgMatches,
mut already_expanded: Vec<String>,
) -> Result<(ArgMatches, GlobalArgs), CliError> {
- if let Some((cmd, args)) = args.subcommand() {
+ if let Some((cmd, sub_args)) = args.subcommand() {
let exec = commands::builtin_exec(cmd);
let aliased_cmd = super::aliased_command(config, cmd);
@@ -271,7 +275,7 @@ fn expand_aliases(
// Here we ignore errors from aliasing as we already favor built-in command,
// and alias doesn't involve in this context.
- if let Some(values) = args.get_many::<OsString>("") {
+ if let Some(values) = sub_args.get_many::<OsString>("") {
// Command is built-in and is not conflicting with alias, but contains ignored values.
return Err(anyhow::format_err!(
"\
@@ -302,17 +306,34 @@ For more information, see issue #10049 <https://github.com/rust-lang/cargo/issue
))?;
}
}
+ if commands::run::is_manifest_command(cmd) {
+ if config.cli_unstable().script {
+ return Ok((args, GlobalArgs::default()));
+ } else {
+ config.shell().warn(format_args!(
+ "\
+user-defined alias `{cmd}` has the appearance of a manfiest-command
+This was previously accepted but will be phased out when `-Zscript` is stabilized.
+For more information, see issue #12207 <https://github.com/rust-lang/cargo/issues/12207>."
+ ))?;
+ }
+ }
let mut alias = alias
.into_iter()
.map(|s| OsString::from(s))
.collect::<Vec<_>>();
- alias.extend(args.get_many::<OsString>("").unwrap_or_default().cloned());
+ alias.extend(
+ sub_args
+ .get_many::<OsString>("")
+ .unwrap_or_default()
+ .cloned(),
+ );
// new_args strips out everything before the subcommand, so
// capture those global options now.
// Note that an alias to an external command will not receive
// these arguments. That may be confusing, but such is life.
- let global_args = GlobalArgs::new(args);
+ let global_args = GlobalArgs::new(sub_args);
let new_args = cli().no_binary_name(true).try_get_matches_from(alias)?;
let new_cmd = new_args.subcommand_name().expect("subcommand is required");
@@ -343,12 +364,26 @@ fn config_configure(
args: &ArgMatches,
subcommand_args: &ArgMatches,
global_args: GlobalArgs,
+ exec: &Exec,
) -> CliResult {
let arg_target_dir = &subcommand_args.value_of_path("target-dir", config);
- let verbose = global_args.verbose + args.verbose();
+ let mut verbose = global_args.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") || subcommand_args.flag("quiet") || global_args.quiet;
+ let mut quiet = args.flag("quiet") || subcommand_args.flag("quiet") || global_args.quiet;
+ if matches!(exec, Exec::Manifest(_)) && !quiet {
+ // Verbosity is shifted quieter for `Exec::Manifest` as it is can be used as if you ran
+ // `cargo install` and we especially shouldn't pollute programmatic output.
+ //
+ // For now, interactive output has the same default output as `cargo run` but that is
+ // subject to change.
+ if let Some(lower) = verbose.checked_sub(1) {
+ verbose = lower;
+ } else if !config.shell().is_err_tty() {
+ // Don't pollute potentially-scripted output
+ quiet = true;
+ }
+ }
let global_color = global_args.color; // Extract so it can take reference.
let color = args
.get_one::<String>("color")
@@ -379,19 +414,65 @@ fn config_configure(
Ok(())
}
-fn execute_subcommand(config: &mut Config, cmd: &str, subcommand_args: &ArgMatches) -> CliResult {
- if let Some(exec) = commands::builtin_exec(cmd) {
- return exec(config, subcommand_args);
+enum Exec {
+ Builtin(commands::Exec),
+ Manifest(String),
+ External(String),
+}
+
+impl Exec {
+ /// Precedence isn't the most obvious from this function because
+ /// - Some is determined by `expand_aliases`
+ /// - Some is enforced by `avoid_ambiguity_between_builtins_and_manifest_commands`
+ ///
+ /// In actuality, it is:
+ /// 1. built-ins xor manifest-command
+ /// 2. aliases
+ /// 3. external subcommands
+ fn infer(cmd: &str) -> CargoResult<Self> {
+ if let Some(exec) = commands::builtin_exec(cmd) {
+ Ok(Self::Builtin(exec))
+ } else if commands::run::is_manifest_command(cmd) {
+ Ok(Self::Manifest(cmd.to_owned()))
+ } else {
+ Ok(Self::External(cmd.to_owned()))
+ }
}
- let mut ext_args: Vec<&OsStr> = vec![OsStr::new(cmd)];
- ext_args.extend(
- subcommand_args
- .get_many::<OsString>("")
- .unwrap_or_default()
- .map(OsString::as_os_str),
- );
- super::execute_external_subcommand(config, cmd, &ext_args)
+ fn exec(self, config: &mut Config, subcommand_args: &ArgMatches) -> CliResult {
+ match self {
+ Self::Builtin(exec) => exec(config, subcommand_args),
+ Self::Manifest(cmd) => {
+ let ext_path = super::find_external_subcommand(config, &cmd);
+ if !config.cli_unstable().script && ext_path.is_some() {
+ config.shell().warn(format_args!(
+ "\
+external subcommand `{cmd}` has the appearance of a manfiest-command
+This was previously accepted but will be phased out when `-Zscript` is stabilized.
+For more information, see issue #12207 <https://github.com/rust-lang/cargo/issues/12207>.",
+ ))?;
+ Self::External(cmd).exec(config, subcommand_args)
+ } else {
+ let ext_args: Vec<OsString> = subcommand_args
+ .get_many::<OsString>("")
+ .unwrap_or_default()
+ .cloned()
+ .collect();
+ commands::run::exec_manifest_command(config, &cmd, &ext_args)
+ }
+ }
+ Self::External(cmd) => {
+ let mut ext_args = vec![OsStr::new(&cmd)];
+ ext_args.extend(
+ subcommand_args
+ .get_many::<OsString>("")
+ .unwrap_or_default()
+ .map(OsString::as_os_str),
+ );
+ super::execute_external_subcommand(config, &cmd, &ext_args)
+ }
+ }
+ }
}
#[derive(Default)]
@@ -435,9 +516,9 @@ pub fn cli() -> Command {
#[allow(clippy::disallowed_methods)]
let is_rustup = std::env::var_os("RUSTUP_HOME").is_some();
let usage = if is_rustup {
- "cargo [+toolchain] [OPTIONS] [COMMAND]"
+ "cargo [+toolchain] [OPTIONS] [COMMAND]\n cargo [+toolchain] [OPTIONS] -Zscript <MANIFEST_RS> [ARGS]..."
} else {
- "cargo [OPTIONS] [COMMAND]"
+ "cargo [OPTIONS] [COMMAND]\n cargo [OPTIONS] -Zscript <MANIFEST> [ARGS]..."
};
Command::new("cargo")
// Subcommands all count their args' display order independently (from 0),
@@ -567,3 +648,14 @@ impl LazyConfig {
fn verify_cli() {
cli().debug_assert();
}
+
+#[test]
+fn avoid_ambiguity_between_builtins_and_manifest_commands() {
+ for cmd in commands::builtin() {
+ let name = cmd.get_name();
+ assert!(
+ !commands::run::is_manifest_command(&name),
+ "built-in command {name} is ambiguous with manifest-commands"
+ )
+ }
+}
diff --git a/src/tools/cargo/src/bin/cargo/commands/add.rs b/src/tools/cargo/src/bin/cargo/commands/add.rs
index 90c4f4dd5..52fc38b74 100644
--- a/src/tools/cargo/src/bin/cargo/commands/add.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/add.rs
@@ -242,7 +242,20 @@ fn parse_dependencies(config: &Config, matches: &ArgMatches) -> CargoResult<Vec<
.flatten()
.map(|c| (Some(c.clone()), None))
.collect::<IndexMap<_, _>>();
+
let mut infer_crate_name = false;
+
+ for (crate_name, _) in crates.iter() {
+ let crate_name = crate_name.as_ref().unwrap();
+
+ if let Some(toolchain) = crate_name.strip_prefix("+") {
+ anyhow::bail!(
+ "invalid character `+` in dependency name: `+{toolchain}`
+ Use `cargo +{toolchain} add` if you meant to use the `{toolchain}` toolchain."
+ );
+ }
+ }
+
if crates.is_empty() {
if path.is_some() || git.is_some() {
crates.insert(None, None);
diff --git a/src/tools/cargo/src/bin/cargo/commands/install.rs b/src/tools/cargo/src/bin/cargo/commands/install.rs
index 8197a1690..3bb90c2d5 100644
--- a/src/tools/cargo/src/bin/cargo/commands/install.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/install.rs
@@ -1,5 +1,6 @@
use crate::command_prelude::*;
+use anyhow::anyhow;
use cargo::core::{GitReference, SourceId, Workspace};
use cargo::ops;
use cargo::util::IntoUrl;
@@ -108,6 +109,16 @@ pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
.map(|k| resolve_crate(k, version))
.collect::<crate::CargoResult<Vec<_>>>()?;
+ for (crate_name, _) in krates.iter() {
+ if let Some(toolchain) = crate_name.strip_prefix("+") {
+ return Err(anyhow!(
+ "invalid character `+` in package name: `+{toolchain}`
+ Use `cargo +{toolchain} install` if you meant to use the `{toolchain}` toolchain."
+ )
+ .into());
+ }
+ }
+
let mut from_cwd = false;
let source = if let Some(url) = args.get_one::<String>("git") {
diff --git a/src/tools/cargo/src/bin/cargo/commands/mod.rs b/src/tools/cargo/src/bin/cargo/commands/mod.rs
index da3109260..b9da0e5fb 100644
--- a/src/tools/cargo/src/bin/cargo/commands/mod.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/mod.rs
@@ -43,7 +43,9 @@ pub fn builtin() -> Vec<Command> {
]
}
-pub fn builtin_exec(cmd: &str) -> Option<fn(&mut Config, &ArgMatches) -> CliResult> {
+pub type Exec = fn(&mut Config, &ArgMatches) -> CliResult;
+
+pub fn builtin_exec(cmd: &str) -> Option<Exec> {
let f = match cmd {
"add" => add::exec,
"bench" => bench::exec,
diff --git a/src/tools/cargo/src/bin/cargo/commands/run.rs b/src/tools/cargo/src/bin/cargo/commands/run.rs
index cde754c7a..366e19396 100644
--- a/src/tools/cargo/src/bin/cargo/commands/run.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/run.rs
@@ -1,6 +1,11 @@
+use std::ffi::OsStr;
+use std::ffi::OsString;
+use std::path::Path;
+
use crate::command_prelude::*;
use crate::util::restricted_names::is_glob_pattern;
use cargo::core::Verbosity;
+use cargo::core::Workspace;
use cargo::ops::{self, CompileFilter, Packages};
use cargo_util::ProcessError;
@@ -13,7 +18,7 @@ pub fn cli() -> Command {
.arg(
Arg::new("args")
.help("Arguments for the binary or example to run")
- .value_parser(value_parser!(std::ffi::OsString))
+ .value_parser(value_parser!(OsString))
.num_args(0..)
.trailing_var_arg(true),
)
@@ -77,27 +82,64 @@ pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
}
};
- ops::run(&ws, &compile_opts, &values_os(args, "args")).map_err(|err| {
- let proc_err = match err.downcast_ref::<ProcessError>() {
- Some(e) => e,
- None => return CliError::new(err, 101),
- };
-
- // If we never actually spawned the process then that sounds pretty
- // bad and we always want to forward that up.
- let exit_code = match proc_err.code {
- Some(exit) => exit,
- None => return CliError::new(err, 101),
- };
-
- // If `-q` was passed then we suppress extra error information about
- // a failed process, we assume the process itself printed out enough
- // information about why it failed so we don't do so as well
- let is_quiet = config.shell().verbosity() == Verbosity::Quiet;
- if is_quiet {
- CliError::code(exit_code)
- } else {
- CliError::new(err, exit_code)
- }
- })
+ ops::run(&ws, &compile_opts, &values_os(args, "args")).map_err(|err| to_run_error(config, err))
+}
+
+/// See also `util/toml/mod.rs`s `is_embedded`
+pub fn is_manifest_command(arg: &str) -> bool {
+ let path = Path::new(arg);
+ 1 < path.components().count()
+ || path.extension() == Some(OsStr::new("rs"))
+ || path.file_name() == Some(OsStr::new("Cargo.toml"))
+}
+
+pub fn exec_manifest_command(config: &mut Config, cmd: &str, args: &[OsString]) -> CliResult {
+ if !config.cli_unstable().script {
+ return Err(anyhow::anyhow!("running `{cmd}` requires `-Zscript`").into());
+ }
+
+ let manifest_path = Path::new(cmd);
+ let manifest_path = root_manifest(Some(manifest_path), config)?;
+
+ // Treat `cargo foo.rs` like `cargo install --path foo` and re-evaluate the config based on the
+ // location where the script resides, rather than the environment from where it's being run.
+ let parent_path = manifest_path
+ .parent()
+ .expect("a file should always have a parent");
+ config.reload_rooted_at(parent_path)?;
+
+ let mut ws = Workspace::new(&manifest_path, config)?;
+ if config.cli_unstable().avoid_dev_deps {
+ ws.set_require_optional_deps(false);
+ }
+
+ let mut compile_opts =
+ cargo::ops::CompileOptions::new(config, cargo::core::compiler::CompileMode::Build)?;
+ compile_opts.spec = cargo::ops::Packages::Default;
+
+ cargo::ops::run(&ws, &compile_opts, args).map_err(|err| to_run_error(config, err))
+}
+
+fn to_run_error(config: &cargo::util::Config, err: anyhow::Error) -> CliError {
+ let proc_err = match err.downcast_ref::<ProcessError>() {
+ Some(e) => e,
+ None => return CliError::new(err, 101),
+ };
+
+ // If we never actually spawned the process then that sounds pretty
+ // bad and we always want to forward that up.
+ let exit_code = match proc_err.code {
+ Some(exit) => exit,
+ None => return CliError::new(err, 101),
+ };
+
+ // If `-q` was passed then we suppress extra error information about
+ // a failed process, we assume the process itself printed out enough
+ // information about why it failed so we don't do so as well
+ let is_quiet = config.shell().verbosity() == Verbosity::Quiet;
+ if is_quiet {
+ CliError::code(exit_code)
+ } else {
+ CliError::new(err, exit_code)
+ }
}
diff --git a/src/tools/cargo/src/bin/cargo/main.rs b/src/tools/cargo/src/bin/cargo/main.rs
index 9fb6635ea..462332fb7 100644
--- a/src/tools/cargo/src/bin/cargo/main.rs
+++ b/src/tools/cargo/src/bin/cargo/main.rs
@@ -2,6 +2,8 @@
#![allow(clippy::all)]
#![warn(clippy::disallowed_methods)]
+use cargo::util::network::http::http_handle;
+use cargo::util::network::http::needs_custom_http_transport;
use cargo::util::toml::StringOrVec;
use cargo::util::CliError;
use cargo::util::{self, closest_msg, command_prelude, CargoResult, CliResult, Config};
@@ -293,12 +295,12 @@ 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) {
- match cargo::ops::needs_custom_http_transport(config) {
+ match needs_custom_http_transport(config) {
Ok(true) => {}
_ => return,
}
- let handle = match cargo::ops::http_handle(config) {
+ let handle = match http_handle(config) {
Ok(handle) => handle,
Err(..) => return,
};
diff --git a/src/tools/cargo/src/cargo/core/compiler/build_config.rs b/src/tools/cargo/src/cargo/core/compiler/build_config.rs
index 885b124b9..5d4d754bf 100644
--- a/src/tools/cargo/src/cargo/core/compiler/build_config.rs
+++ b/src/tools/cargo/src/cargo/core/compiler/build_config.rs
@@ -1,4 +1,5 @@
use crate::core::compiler::CompileKind;
+use crate::util::config::JobsConfig;
use crate::util::interning::InternedString;
use crate::util::{CargoResult, Config, RustfixDiagnosticServer};
use anyhow::{bail, Context as _};
@@ -64,7 +65,7 @@ impl BuildConfig {
/// * `target.$target.libfoo.metadata`
pub fn new(
config: &Config,
- jobs: Option<i32>,
+ jobs: Option<JobsConfig>,
keep_going: bool,
requested_targets: &[String],
mode: CompileMode,
@@ -78,11 +79,22 @@ impl BuildConfig {
its environment, ignoring the `-j` parameter",
)?;
}
- let jobs = match jobs.or(cfg.jobs) {
+ let jobs = match jobs.or(cfg.jobs.clone()) {
None => default_parallelism()?,
- Some(0) => anyhow::bail!("jobs may not be 0"),
- Some(j) if j < 0 => (default_parallelism()? as i32 + j).max(1) as u32,
- Some(j) => j as u32,
+ Some(value) => match value {
+ JobsConfig::Integer(j) => match j {
+ 0 => anyhow::bail!("jobs may not be 0"),
+ j if j < 0 => (default_parallelism()? as i32 + j).max(1) as u32,
+ j => j as u32,
+ },
+ JobsConfig::String(j) => match j.as_str() {
+ "default" => default_parallelism()?,
+ _ => {
+ anyhow::bail!(
+ format!("could not parse `{j}`. Number of parallel jobs should be `default` or a number."))
+ }
+ },
+ },
};
if config.cli_unstable().build_std.is_some() && requested_kinds[0].is_host() {
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 01890e542..d17462174 100644
--- a/src/tools/cargo/src/cargo/core/compiler/custom_build.rs
+++ b/src/tools/cargo/src/cargo/core/compiler/custom_build.rs
@@ -31,7 +31,7 @@
//! [`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 super::{fingerprint, Context, Job, Unit, Work};
use crate::core::compiler::artifact;
use crate::core::compiler::context::Metadata;
use crate::core::compiler::job_queue::JobState;
@@ -62,7 +62,7 @@ pub struct BuildOutput {
/// Names and link kinds of libraries, suitable for the `-l` flag.
pub library_links: Vec<String>,
/// Linker arguments suitable to be passed to `-C link-arg=<args>`
- pub linker_args: Vec<(LinkType, String)>,
+ pub linker_args: Vec<(LinkArgTarget, String)>,
/// Various `--cfg` flags to pass to the compiler.
pub cfgs: Vec<String>,
/// Various `--check-cfg` flags to pass to the compiler.
@@ -146,6 +146,47 @@ pub struct BuildDeps {
pub rerun_if_env_changed: Vec<String>,
}
+/// Represents one of the instructions from `cargo:rustc-link-arg-*` build
+/// script instruction family.
+///
+/// In other words, indicates targets that custom linker arguments applies to.
+///
+/// See the [build script documentation][1] for more.
+///
+/// [1]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#cargorustc-link-argflag
+#[derive(Clone, Hash, Debug, PartialEq, Eq)]
+pub enum LinkArgTarget {
+ /// Represents `cargo:rustc-link-arg=FLAG`.
+ All,
+ /// Represents `cargo:rustc-cdylib-link-arg=FLAG`.
+ Cdylib,
+ /// Represents `cargo:rustc-link-arg-bins=FLAG`.
+ Bin,
+ /// Represents `cargo:rustc-link-arg-bin=BIN=FLAG`.
+ SingleBin(String),
+ /// Represents `cargo:rustc-link-arg-tests=FLAG`.
+ Test,
+ /// Represents `cargo:rustc-link-arg-benches=FLAG`.
+ Bench,
+ /// Represents `cargo:rustc-link-arg-examples=FLAG`.
+ Example,
+}
+
+impl LinkArgTarget {
+ /// Checks if this link type applies to a given [`Target`].
+ pub fn applies_to(&self, target: &Target) -> bool {
+ match self {
+ LinkArgTarget::All => true,
+ LinkArgTarget::Cdylib => target.is_cdylib(),
+ LinkArgTarget::Bin => target.is_bin(),
+ LinkArgTarget::SingleBin(name) => target.is_bin() && target.name() == name,
+ LinkArgTarget::Test => target.is_test(),
+ LinkArgTarget::Bench => target.is_bench(),
+ LinkArgTarget::Example => target.is_exe_example(),
+ }
+ }
+}
+
/// Prepares a `Work` that executes the target as a custom build script.
pub fn prepare(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Job> {
let _p = profile::start(format!(
@@ -711,10 +752,10 @@ impl BuildOutput {
key, pkg_descr
));
}
- linker_args.push((LinkType::Cdylib, value))
+ linker_args.push((LinkArgTarget::Cdylib, value))
}
"rustc-link-arg-bins" => {
- check_and_add_target!("bin", Target::is_bin, LinkType::Bin);
+ check_and_add_target!("bin", Target::is_bin, LinkArgTarget::Bin);
}
"rustc-link-arg-bin" => {
let mut parts = value.splitn(2, '=');
@@ -742,19 +783,19 @@ impl BuildOutput {
bin_name
);
}
- linker_args.push((LinkType::SingleBin(bin_name), arg.to_string()));
+ linker_args.push((LinkArgTarget::SingleBin(bin_name), arg.to_string()));
}
"rustc-link-arg-tests" => {
- check_and_add_target!("test", Target::is_test, LinkType::Test);
+ check_and_add_target!("test", Target::is_test, LinkArgTarget::Test);
}
"rustc-link-arg-benches" => {
- check_and_add_target!("benchmark", Target::is_bench, LinkType::Bench);
+ check_and_add_target!("benchmark", Target::is_bench, LinkArgTarget::Bench);
}
"rustc-link-arg-examples" => {
- check_and_add_target!("example", Target::is_example, LinkType::Example);
+ check_and_add_target!("example", Target::is_example, LinkArgTarget::Example);
}
"rustc-link-arg" => {
- linker_args.push((LinkType::All, value));
+ linker_args.push((LinkArgTarget::All, value));
}
"rustc-cfg" => cfgs.push(value.to_string()),
"rustc-check-cfg" => {
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 a3523110b..aa8be50f7 100644
--- a/src/tools/cargo/src/cargo/core/compiler/fingerprint/mod.rs
+++ b/src/tools/cargo/src/cargo/core/compiler/fingerprint/mod.rs
@@ -1,8 +1,11 @@
-//! # Fingerprints
+//! Tracks changes to determine if something needs to be recompiled.
//!
//! This module implements change-tracking so that Cargo can know whether or
//! not something needs to be recompiled. A Cargo [`Unit`] can be either "dirty"
//! (needs to be recompiled) or "fresh" (it does not need to be recompiled).
+//!
+//! ## Mechanisms affecting freshness
+//!
//! There are several mechanisms that influence a Unit's freshness:
//!
//! - The [`Fingerprint`] is a hash, saved to the filesystem in the
diff --git a/src/tools/cargo/src/cargo/core/compiler/mod.rs b/src/tools/cargo/src/cargo/core/compiler/mod.rs
index 7e49f0079..31e63c226 100644
--- a/src/tools/cargo/src/cargo/core/compiler/mod.rs
+++ b/src/tools/cargo/src/cargo/core/compiler/mod.rs
@@ -76,6 +76,7 @@ pub use self::compilation::{Compilation, Doctest, UnitOutput};
pub use self::compile_kind::{CompileKind, CompileTarget};
pub use self::context::{Context, Metadata};
pub use self::crate_type::CrateType;
+pub use self::custom_build::LinkArgTarget;
pub use self::custom_build::{BuildOutput, BuildScriptOutputs, BuildScripts};
pub(crate) use self::fingerprint::DirtyReason;
pub use self::job_queue::Freshness;
@@ -99,44 +100,6 @@ use rustfix::diagnostics::Applicability;
const RUSTDOC_CRATE_VERSION_FLAG: &str = "--crate-version";
-// TODO: Rename this to `ExtraLinkArgFor` or else, and move to compiler/custom_build.rs?
-/// Represents one of the instruction from `cargo:rustc-link-arg-*` build script
-/// instruction family.
-///
-/// In other words, indicates targets that custom linker arguments applies to.
-#[derive(Clone, Hash, Debug, PartialEq, Eq)]
-pub enum LinkType {
- /// Represents `cargo:rustc-link-arg=FLAG`.
- All,
- /// Represents `cargo:rustc-cdylib-link-arg=FLAG`.
- Cdylib,
- /// Represents `cargo:rustc-link-arg-bins=FLAG`.
- Bin,
- /// Represents `cargo:rustc-link-arg-bin=BIN=FLAG`.
- SingleBin(String),
- /// Represents `cargo:rustc-link-arg-tests=FLAG`.
- Test,
- /// Represents `cargo:rustc-link-arg-benches=FLAG`.
- Bench,
- /// Represents `cargo:rustc-link-arg-examples=FLAG`.
- Example,
-}
-
-impl LinkType {
- /// Checks if this link type applies to a given [`Target`].
- pub fn applies_to(&self, target: &Target) -> bool {
- match self {
- LinkType::All => true,
- LinkType::Cdylib => target.is_cdylib(),
- LinkType::Bin => target.is_bin(),
- LinkType::SingleBin(name) => target.is_bin() && target.name() == name,
- LinkType::Test => target.is_test(),
- LinkType::Bench => target.is_bench(),
- LinkType::Example => target.is_exe_example(),
- }
- }
-}
-
/// A glorified callback for executing calls to rustc. Rather than calling rustc
/// directly, we'll use an `Executor`, giving clients an opportunity to intercept
/// the build calls.
@@ -286,14 +249,12 @@ fn make_failed_scrape_diagnostic(
/// Creates a unit of work invoking `rustc` for building the `unit`.
fn rustc(cx: &mut Context<'_, '_>, unit: &Unit, exec: &Arc<dyn Executor>) -> CargoResult<Work> {
- let mut rustc = prepare_rustc(cx, &unit.target.rustc_crate_types(), unit)?;
+ let mut rustc = prepare_rustc(cx, unit)?;
let build_plan = cx.bcx.build_config.build_plan;
let name = unit.pkg.name().to_string();
let buildkey = unit.buildkey();
- add_cap_lints(cx.bcx, unit, &mut rustc);
-
let outputs = cx.outputs(unit)?;
let root = cx.files().out_dir(unit);
@@ -319,10 +280,6 @@ fn rustc(cx: &mut Context<'_, '_>, unit: &Unit, exec: &Arc<dyn Executor>) -> Car
let rustc_dep_info_loc = root.join(dep_info_name);
let dep_info_loc = fingerprint::dep_info_loc(cx, unit);
- rustc.args(cx.bcx.rustflags_args(unit));
- if cx.bcx.config.cli_unstable().binary_dep_depinfo {
- rustc.arg("-Z").arg("binary-dep-depinfo");
- }
let mut output_options = OutputOptions::new(cx, unit);
let package_id = unit.pkg.package_id();
let target = Target::clone(&unit.target);
@@ -544,7 +501,7 @@ fn rustc(cx: &mut Context<'_, '_>, unit: &Unit, exec: &Arc<dyn Executor>) -> Car
// clause should have been kept in the `if` block above. For
// now, continue allowing it for cdylib only.
// See https://github.com/rust-lang/cargo/issues/9562
- if lt.applies_to(target) && (key.0 == current_id || *lt == LinkType::Cdylib) {
+ if lt.applies_to(target) && (key.0 == current_id || *lt == LinkArgTarget::Cdylib) {
rustc.arg("-C").arg(format!("link-arg={}", arg));
}
}
@@ -604,7 +561,7 @@ fn link_targets(cx: &mut Context<'_, '_>, unit: &Unit, fresh: bool) -> CargoResu
}
if json_messages {
- let debuginfo = profile.debuginfo.to_option().map(|d| match d {
+ let debuginfo = match profile.debuginfo.into_inner() {
TomlDebugInfo::None => machine_message::ArtifactDebuginfo::Int(0),
TomlDebugInfo::Limited => machine_message::ArtifactDebuginfo::Int(1),
TomlDebugInfo::Full => machine_message::ArtifactDebuginfo::Int(2),
@@ -614,10 +571,10 @@ fn link_targets(cx: &mut Context<'_, '_>, unit: &Unit, fresh: bool) -> CargoResu
TomlDebugInfo::LineTablesOnly => {
machine_message::ArtifactDebuginfo::Named("line-tables-only")
}
- });
+ };
let art_profile = machine_message::ArtifactProfile {
opt_level: profile.opt_level.as_str(),
- debuginfo,
+ debuginfo: Some(debuginfo),
debug_assertions: profile.debug_assertions,
overflow_checks: profile.overflow_checks,
test: unit_mode.is_any_test(),
@@ -705,13 +662,13 @@ where
search_path
}
-// TODO: do we really need this as a separate function?
-// Maybe we should reorganize `rustc` fn to make it more traceable and readable.
-fn prepare_rustc(
- cx: &mut Context<'_, '_>,
- crate_types: &[CrateType],
- unit: &Unit,
-) -> CargoResult<ProcessBuilder> {
+/// Prepares flags and environments we can compute for a `rustc` invocation
+/// before the job queue starts compiling any unit.
+///
+/// This builds a static view of the invocation. Flags depending on the
+/// completion of other units will be added later in runtime, such as flags
+/// from build scripts.
+fn prepare_rustc(cx: &Context<'_, '_>, unit: &Unit) -> CargoResult<ProcessBuilder> {
let is_primary = cx.is_primary_package(unit);
let is_workspace = cx.bcx.ws.is_member(&unit.pkg);
@@ -729,13 +686,23 @@ fn prepare_rustc(
}
base.inherit_jobserver(&cx.jobserver);
- build_base_args(cx, &mut base, unit, crate_types)?;
+ build_base_args(cx, &mut base, unit)?;
build_deps_args(&mut base, cx, unit)?;
+ add_cap_lints(cx.bcx, unit, &mut base);
+ base.args(cx.bcx.rustflags_args(unit));
+ if cx.bcx.config.cli_unstable().binary_dep_depinfo {
+ base.arg("-Z").arg("binary-dep-depinfo");
+ }
Ok(base)
}
-/// Creates a unit of work invoking `rustdoc` for documenting the `unit`.
-fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> {
+/// Prepares flags and environments we can compute for a `rustdoc` invocation
+/// before the job queue starts compiling any unit.
+///
+/// This builds a static view of the invocation. Flags depending on the
+/// completion of other units will be added later in runtime, such as flags
+/// from build scripts.
+fn prepare_rustdoc(cx: &Context<'_, '_>, unit: &Unit) -> CargoResult<ProcessBuilder> {
let bcx = cx.bcx;
// script_metadata is not needed here, it is only for tests.
let mut rustdoc = cx.compilation.rustdoc_process(unit, None)?;
@@ -749,12 +716,6 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> {
rustdoc.arg("--target").arg(target.rustc_target());
}
let doc_dir = cx.files().out_dir(unit);
-
- // Create the documentation directory ahead of time as rustdoc currently has
- // a bug where concurrent invocations will race to create this directory if
- // it doesn't already exist.
- paths::create_dir_all(&doc_dir)?;
-
rustdoc.arg("-o").arg(&doc_dir);
rustdoc.args(&features_args(unit));
rustdoc.args(&check_cfg_args(cx, unit));
@@ -770,10 +731,6 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> {
let metadata = cx.metadata_for_doc_units[unit];
rustdoc.arg("-C").arg(format!("metadata={}", metadata));
- let scrape_output_path = |unit: &Unit| -> CargoResult<PathBuf> {
- cx.outputs(unit).map(|outputs| outputs[0].path.clone())
- };
-
if unit.mode.is_doc_scrape() {
debug_assert!(cx.bcx.scrape_units.contains(unit));
@@ -785,7 +742,7 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> {
rustdoc
.arg("--scrape-examples-output-path")
- .arg(scrape_output_path(unit)?);
+ .arg(scrape_output_path(cx, unit)?);
// Only scrape example for items from crates in the workspace, to reduce generated file size
for pkg in cx.bcx.ws.members() {
@@ -800,21 +757,9 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> {
}
}
- let should_include_scrape_units = unit.mode.is_doc()
- && cx.bcx.scrape_units.len() > 0
- && cx.bcx.ws.unit_needs_doc_scrape(unit);
- let scrape_outputs = if should_include_scrape_units {
+ if should_include_scrape_units(cx.bcx, unit) {
rustdoc.arg("-Zunstable-options");
- Some(
- cx.bcx
- .scrape_units
- .iter()
- .map(|unit| Ok((cx.files().metadata(unit), scrape_output_path(unit)?)))
- .collect::<CargoResult<HashMap<_, _>>>()?,
- )
- } else {
- None
- };
+ }
build_deps_args(&mut rustdoc, cx, unit)?;
rustdoc::add_root_urls(cx, unit, &mut rustdoc)?;
@@ -825,6 +770,20 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> {
append_crate_version_flag(unit, &mut rustdoc);
}
+ Ok(rustdoc)
+}
+
+/// Creates a unit of work invoking `rustdoc` for documenting the `unit`.
+fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> {
+ let mut rustdoc = prepare_rustdoc(cx, unit)?;
+
+ let crate_name = unit.target.crate_name();
+ let doc_dir = cx.files().out_dir(unit);
+ // Create the documentation directory ahead of time as rustdoc currently has
+ // a bug where concurrent invocations will race to create this directory if
+ // it doesn't already exist.
+ paths::create_dir_all(&doc_dir)?;
+
let target_desc = unit.target.description_named();
let name = unit.pkg.name().to_string();
let build_script_outputs = Arc::clone(&cx.build_script_outputs);
@@ -833,6 +792,17 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> {
let target = Target::clone(&unit.target);
let mut output_options = OutputOptions::new(cx, unit);
let script_metadata = cx.find_build_script_metadata(unit);
+ let scrape_outputs = if should_include_scrape_units(cx.bcx, unit) {
+ Some(
+ cx.bcx
+ .scrape_units
+ .iter()
+ .map(|unit| Ok((cx.files().metadata(unit), scrape_output_path(cx, unit)?)))
+ .collect::<CargoResult<HashMap<_, _>>>()?,
+ )
+ } else {
+ None
+ };
let failed_scrape_units = Arc::clone(&cx.failed_scrape_units);
let hide_diagnostics_for_scrape_unit = cx.bcx.unit_can_fail_for_docscraping(unit)
@@ -977,12 +947,7 @@ fn add_error_format_and_color(cx: &Context<'_, '_>, cmd: &mut ProcessBuilder) {
}
/// Adds essential rustc flags and environment variables to the command to execute.
-fn build_base_args(
- cx: &mut Context<'_, '_>,
- cmd: &mut ProcessBuilder,
- unit: &Unit,
- crate_types: &[CrateType],
-) -> CargoResult<()> {
+fn build_base_args(cx: &Context<'_, '_>, cmd: &mut ProcessBuilder, unit: &Unit) -> CargoResult<()> {
assert!(!unit.mode.is_run_custom_build());
let bcx = cx.bcx;
@@ -998,7 +963,7 @@ fn build_base_args(
ref panic,
incremental,
strip,
- rustflags,
+ rustflags: profile_rustflags,
..
} = unit.profile.clone();
let test = unit.mode.is_any_test();
@@ -1014,7 +979,7 @@ fn build_base_args(
let mut contains_dy_lib = false;
if !test {
- for crate_type in crate_types {
+ for crate_type in &unit.target.rustc_crate_types() {
cmd.arg("--crate-type").arg(crate_type.as_str());
contains_dy_lib |= crate_type == &CrateType::Dylib;
}
@@ -1047,22 +1012,6 @@ fn build_base_args(
cmd.args(&lto_args(cx, unit));
- // This is generally just an optimization on build time so if we don't pass
- // it then it's ok. The values for the flag (off, packed, unpacked) may be supported
- // or not depending on the platform, so availability is checked per-value.
- // For example, at the time of writing this code, on Windows the only stable valid
- // value for split-debuginfo is "packed", while on Linux "unpacked" is also stable.
- if let Some(split) = split_debuginfo {
- if cx
- .bcx
- .target_data
- .info(unit.kind)
- .supports_debuginfo_split(split)
- {
- cmd.arg("-C").arg(format!("split-debuginfo={}", split));
- }
- }
-
if let Some(backend) = codegen_backend {
cmd.arg("-Z").arg(&format!("codegen-backend={}", backend));
}
@@ -1071,14 +1020,30 @@ fn build_base_args(
cmd.arg("-C").arg(&format!("codegen-units={}", n));
}
- if let Some(debuginfo) = debuginfo.to_option() {
- cmd.arg("-C").arg(format!("debuginfo={}", debuginfo));
+ let debuginfo = debuginfo.into_inner();
+ // Shorten the number of arguments if possible.
+ if debuginfo != TomlDebugInfo::None {
+ cmd.arg("-C").arg(format!("debuginfo={debuginfo}"));
+ // This is generally just an optimization on build time so if we don't
+ // pass it then it's ok. The values for the flag (off, packed, unpacked)
+ // may be supported or not depending on the platform, so availability is
+ // checked per-value. For example, at the time of writing this code, on
+ // Windows the only stable valid value for split-debuginfo is "packed",
+ // while on Linux "unpacked" is also stable.
+ if let Some(split) = split_debuginfo {
+ if cx
+ .bcx
+ .target_data
+ .info(unit.kind)
+ .supports_debuginfo_split(split)
+ {
+ cmd.arg("-C").arg(format!("split-debuginfo={split}"));
+ }
+ }
}
cmd.args(unit.pkg.manifest().lint_rustflags());
- if !rustflags.is_empty() {
- cmd.args(&rustflags);
- }
+ cmd.args(&profile_rustflags);
if let Some(args) = cx.bcx.extra_args_for(unit) {
cmd.args(args);
}
@@ -1277,11 +1242,7 @@ fn lto_args(cx: &Context<'_, '_>, unit: &Unit) -> Vec<OsString> {
///
/// [`-L`]: https://doc.rust-lang.org/nightly/rustc/command-line-arguments.html#-l-add-a-directory-to-the-library-search-path
/// [`--extern`]: https://doc.rust-lang.org/nightly/rustc/command-line-arguments.html#--extern-specify-where-an-external-library-is-located
-fn build_deps_args(
- cmd: &mut ProcessBuilder,
- cx: &mut Context<'_, '_>,
- unit: &Unit,
-) -> CargoResult<()> {
+fn build_deps_args(cmd: &mut ProcessBuilder, cx: &Context<'_, '_>, unit: &Unit) -> CargoResult<()> {
let bcx = cx.bcx;
cmd.arg("-L").arg(&{
let mut deps = OsString::from("dependency=");
@@ -1821,3 +1782,14 @@ fn apply_env_config(config: &crate::Config, cmd: &mut ProcessBuilder) -> CargoRe
}
Ok(())
}
+
+/// Checks if there are some scrape units waiting to be processed.
+fn should_include_scrape_units(bcx: &BuildContext<'_, '_>, unit: &Unit) -> bool {
+ unit.mode.is_doc() && bcx.scrape_units.len() > 0 && bcx.ws.unit_needs_doc_scrape(unit)
+}
+
+/// Gets the file path of function call information output from `rustdoc`.
+fn scrape_output_path(cx: &Context<'_, '_>, unit: &Unit) -> CargoResult<PathBuf> {
+ assert!(unit.mode.is_doc() || unit.mode.is_doc_scrape());
+ cx.outputs(unit).map(|outputs| outputs[0].path.clone())
+}
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 3bf8b0c77..369fd8318 100644
--- a/src/tools/cargo/src/cargo/core/compiler/unit_dependencies.rs
+++ b/src/tools/cargo/src/cargo/core/compiler/unit_dependencies.rs
@@ -1,4 +1,4 @@
-//! # Constructs the dependency graph for compilation
+//! Constructs the dependency graph for compilation.
//!
//! Rust code is typically organized as a set of Cargo packages. The
//! dependencies between the packages themselves are stored in the
diff --git a/src/tools/cargo/src/cargo/core/features.rs b/src/tools/cargo/src/cargo/core/features.rs
index d56054a0a..9b99d5a15 100644
--- a/src/tools/cargo/src/cargo/core/features.rs
+++ b/src/tools/cargo/src/cargo/core/features.rs
@@ -687,6 +687,26 @@ macro_rules! unstable_cli_options {
fields
}
}
+
+ #[cfg(test)]
+ mod test {
+ #[test]
+ fn ensure_sorted() {
+ // This will be printed out if the fields are not sorted.
+ let location = std::panic::Location::caller();
+ println!(
+ "\nTo fix this test, sort the features inside the macro at {}:{}\n",
+ location.file(),
+ location.line()
+ );
+ let mut expected = vec![$(stringify!($element)),*];
+ expected[2..].sort();
+ snapbox::assert_eq(
+ format!("{:#?}", expected),
+ format!("{:#?}", vec![$(stringify!($element)),*])
+ );
+ }
+ }
}
}
@@ -696,7 +716,7 @@ unstable_cli_options!(
print_im_a_teapot: bool = (HIDDEN),
// All other unstable features.
- // Please keep this list lexiographically ordered.
+ // Please keep this list lexicographically ordered.
advanced_env: bool = (HIDDEN),
avoid_dev_deps: bool = ("Avoid installing dev-dependencies if possible"),
binary_dep_depinfo: bool = ("Track changes to dependency artifacts"),
@@ -704,34 +724,34 @@ unstable_cli_options!(
#[serde(deserialize_with = "deserialize_build_std")]
build_std: Option<Vec<String>> = ("Enable Cargo to compile the standard library itself as part of a crate graph compilation"),
build_std_features: Option<Vec<String>> = ("Configure features enabled for the standard library itself when building the standard library"),
+ #[serde(deserialize_with = "deserialize_check_cfg")]
+ check_cfg: Option<(/*features:*/ bool, /*well_known_names:*/ bool, /*well_known_values:*/ bool, /*output:*/ bool)> = ("Specify scope of compile-time checking of `cfg` names/values"),
codegen_backend: bool = ("Enable the `codegen-backend` option in profiles in .cargo/config.toml file"),
config_include: bool = ("Enable the `include` key in config files"),
credential_process: bool = ("Add a config setting to fetch registry authentication tokens by calling an external process"),
- #[serde(deserialize_with = "deserialize_check_cfg")]
- check_cfg: Option<(/*features:*/ bool, /*well_known_names:*/ bool, /*well_known_values:*/ bool, /*output:*/ bool)> = ("Specify scope of compile-time checking of `cfg` names/values"),
- doctest_in_workspace: bool = ("Compile doctests with paths relative to the workspace root"),
+ direct_minimal_versions: bool = ("Resolve minimal dependency versions instead of maximum (direct dependencies only)"),
doctest_xcompile: bool = ("Compile and run doctests for non-host target using runner config"),
dual_proc_macros: bool = ("Build proc-macros for both the host and the target"),
features: Option<Vec<String>> = (HIDDEN),
gitoxide: Option<GitoxideFeatures> = ("Use gitoxide for the given git interactions, or all of them if no argument is given"),
- jobserver_per_rustc: bool = (HIDDEN),
+ host_config: bool = ("Enable the [host] section in the .cargo/config.toml file"),
+ lints: bool = ("Pass `[lints]` to the linting tools"),
minimal_versions: bool = ("Resolve minimal dependency versions instead of maximum"),
- direct_minimal_versions: bool = ("Resolve minimal dependency versions instead of maximum (direct dependencies only)"),
+ msrv_policy: bool = ("Enable rust-version aware policy within cargo"),
mtime_on_use: bool = ("Configure Cargo to update the mtime of used files"),
+ next_lockfile_bump: bool = (HIDDEN),
no_index_update: bool = ("Do not update the registry index even if the cache is outdated"),
panic_abort_tests: bool = ("Enable support to run tests with -Cpanic=abort"),
profile_rustflags: bool = ("Enable the `rustflags` option in profiles in .cargo/config.toml file"),
- host_config: bool = ("Enable the [host] section in the .cargo/config.toml file"),
+ publish_timeout: bool = ("Enable the `publish.timeout` key in .cargo/config.toml file"),
registry_auth: bool = ("Authentication for alternative registries, and generate registry authentication tokens using asymmetric cryptography"),
- target_applies_to_host: bool = ("Enable the `target-applies-to-host` key in the .cargo/config.toml file"),
rustdoc_map: bool = ("Allow passing external documentation mappings to rustdoc"),
+ rustdoc_scrape_examples: bool = ("Allows Rustdoc to scrape code examples from reverse-dependencies"),
+ script: bool = ("Enable support for single-file, `.rs` packages"),
separate_nightlies: bool = (HIDDEN),
- publish_timeout: bool = ("Enable the `publish.timeout` key in .cargo/config.toml file"),
- 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"),
+ target_applies_to_host: bool = ("Enable the `target-applies-to-host` key in the .cargo/config.toml file"),
+ unstable_options: bool = ("Allow the usage of unstable options"),
);
const STABILIZED_COMPILE_PROGRESS: &str = "The progress bar is now always \
@@ -779,6 +799,9 @@ const STABILIZED_NAMED_PROFILES: &str = "The named-profiles feature is now alway
See https://doc.rust-lang.org/nightly/cargo/reference/profiles.html#custom-profiles \
for more information";
+const STABILIZED_DOCTEST_IN_WORKSPACE: &str =
+ "The doctest-in-workspace feature is now always enabled.";
+
const STABILIZED_FUTURE_INCOMPAT_REPORT: &str =
"The future-incompat-report feature is now always enabled.";
@@ -1011,41 +1034,19 @@ impl CliUnstable {
}
match k {
- "print-im-a-teapot" => self.print_im_a_teapot = parse_bool(k, v)?,
+ // Permanently unstable features
+ // Sorted alphabetically:
"allow-features" => self.allow_features = Some(parse_features(v).into_iter().collect()),
- "unstable-options" => self.unstable_options = parse_empty(k, v)?,
- "no-index-update" => self.no_index_update = parse_empty(k, v)?,
- "avoid-dev-deps" => self.avoid_dev_deps = parse_empty(k, v)?,
- "minimal-versions" => self.minimal_versions = parse_empty(k, v)?,
- "direct-minimal-versions" => self.direct_minimal_versions = parse_empty(k, v)?,
- "advanced-env" => self.advanced_env = parse_empty(k, v)?,
- "config-include" => self.config_include = parse_empty(k, v)?,
- "check-cfg" => {
- self.check_cfg = v.map_or(Ok(None), |v| parse_check_cfg(v.split(',')))?
- }
- "dual-proc-macros" => self.dual_proc_macros = parse_empty(k, v)?,
- // can also be set in .cargo/config or with and ENV
- "mtime-on-use" => self.mtime_on_use = parse_empty(k, v)?,
- "named-profiles" => stabilized_warn(k, "1.57", STABILIZED_NAMED_PROFILES),
- "binary-dep-depinfo" => self.binary_dep_depinfo = parse_empty(k, v)?,
- "bindeps" => self.bindeps = parse_empty(k, v)?,
- "build-std" => {
- self.build_std = Some(crate::core::compiler::standard_lib::parse_unstable_flag(v))
- }
- "build-std-features" => self.build_std_features = Some(parse_features(v)),
- "doctest-xcompile" => self.doctest_xcompile = parse_empty(k, v)?,
- "doctest-in-workspace" => self.doctest_in_workspace = parse_empty(k, v)?,
- "panic-abort-tests" => self.panic_abort_tests = parse_empty(k, v)?,
- "jobserver-per-rustc" => self.jobserver_per_rustc = parse_empty(k, v)?,
- "gitoxide" => {
- self.gitoxide = v.map_or_else(
- || Ok(Some(GitoxideFeatures::all())),
- |v| parse_gitoxide(v.split(',')),
- )?
- }
- "host-config" => self.host_config = parse_empty(k, v)?,
- "target-applies-to-host" => self.target_applies_to_host = parse_empty(k, v)?,
- "publish-timeout" => self.publish_timeout = parse_empty(k, v)?,
+ "print-im-a-teapot" => self.print_im_a_teapot = parse_bool(k, v)?,
+
+ // Stabilized features
+ // Sorted by version, then alphabetically:
+ "compile-progress" => stabilized_warn(k, "1.30", STABILIZED_COMPILE_PROGRESS),
+ "offline" => stabilized_err(k, "1.36", STABILIZED_OFFLINE)?,
+ "cache-messages" => stabilized_warn(k, "1.40", STABILIZED_CACHE_MESSAGES),
+ "install-upgrade" => stabilized_warn(k, "1.41", STABILIZED_INSTALL_UPGRADE),
+ "config-profile" => stabilized_warn(k, "1.43", STABILIZED_CONFIG_PROFILE),
+ "crate-versions" => stabilized_warn(k, "1.47", STABILIZED_CRATE_VERSIONS),
"features" => {
// `-Z features` has been stabilized since 1.51,
// but `-Z features=compare` is still allowed for convenience
@@ -1067,35 +1068,66 @@ impl CliUnstable {
}
self.features = Some(feats);
}
- "separate-nightlies" => self.separate_nightlies = parse_empty(k, v)?,
- "multitarget" => stabilized_warn(k, "1.64", STABILISED_MULTITARGET),
- "rustdoc-map" => self.rustdoc_map = parse_empty(k, v)?,
- "terminal-width" => stabilized_warn(k, "1.68", STABILIZED_TERMINAL_WIDTH),
- "sparse-registry" => stabilized_warn(k, "1.68", STABILISED_SPARSE_REGISTRY),
- "registry-auth" => self.registry_auth = parse_empty(k, v)?,
- "namespaced-features" => stabilized_warn(k, "1.60", STABILISED_NAMESPACED_FEATURES),
- "weak-dep-features" => stabilized_warn(k, "1.60", STABILIZED_WEAK_DEP_FEATURES),
- "credential-process" => self.credential_process = parse_empty(k, v)?,
- "rustdoc-scrape-examples" => self.rustdoc_scrape_examples = parse_empty(k, v)?,
- "skip-rustdoc-fingerprint" => self.skip_rustdoc_fingerprint = parse_empty(k, v)?,
- "compile-progress" => stabilized_warn(k, "1.30", STABILIZED_COMPILE_PROGRESS),
- "offline" => stabilized_err(k, "1.36", STABILIZED_OFFLINE)?,
- "cache-messages" => stabilized_warn(k, "1.40", STABILIZED_CACHE_MESSAGES),
- "install-upgrade" => stabilized_warn(k, "1.41", STABILIZED_INSTALL_UPGRADE),
- "config-profile" => stabilized_warn(k, "1.43", STABILIZED_CONFIG_PROFILE),
- "crate-versions" => stabilized_warn(k, "1.47", STABILIZED_CRATE_VERSIONS),
"package-features" => stabilized_warn(k, "1.51", STABILIZED_PACKAGE_FEATURES),
- "extra-link-arg" => stabilized_warn(k, "1.56", STABILIZED_EXTRA_LINK_ARG),
"configurable-env" => stabilized_warn(k, "1.56", STABILIZED_CONFIGURABLE_ENV),
+ "extra-link-arg" => stabilized_warn(k, "1.56", STABILIZED_EXTRA_LINK_ARG),
"patch-in-config" => stabilized_warn(k, "1.56", STABILIZED_PATCH_IN_CONFIG),
+ "named-profiles" => stabilized_warn(k, "1.57", STABILIZED_NAMED_PROFILES),
"future-incompat-report" => {
stabilized_warn(k, "1.59.0", STABILIZED_FUTURE_INCOMPAT_REPORT)
}
+ "namespaced-features" => stabilized_warn(k, "1.60", STABILISED_NAMESPACED_FEATURES),
"timings" => stabilized_warn(k, "1.60", STABILIZED_TIMINGS),
+ "weak-dep-features" => stabilized_warn(k, "1.60", STABILIZED_WEAK_DEP_FEATURES),
+ "multitarget" => stabilized_warn(k, "1.64", STABILISED_MULTITARGET),
+ "sparse-registry" => stabilized_warn(k, "1.68", STABILISED_SPARSE_REGISTRY),
+ "terminal-width" => stabilized_warn(k, "1.68", STABILIZED_TERMINAL_WIDTH),
+ "doctest-in-workspace" => stabilized_warn(k, "1.72", STABILIZED_DOCTEST_IN_WORKSPACE),
+
+ // Unstable features
+ // Sorted alphabetically:
+ "advanced-env" => self.advanced_env = parse_empty(k, v)?,
+ "avoid-dev-deps" => self.avoid_dev_deps = parse_empty(k, v)?,
+ "binary-dep-depinfo" => self.binary_dep_depinfo = parse_empty(k, v)?,
+ "bindeps" => self.bindeps = parse_empty(k, v)?,
+ "build-std" => {
+ self.build_std = Some(crate::core::compiler::standard_lib::parse_unstable_flag(v))
+ }
+ "build-std-features" => self.build_std_features = Some(parse_features(v)),
+ "check-cfg" => {
+ self.check_cfg = v.map_or(Ok(None), |v| parse_check_cfg(v.split(',')))?
+ }
"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)?,
+ "config-include" => self.config_include = parse_empty(k, v)?,
+ "credential-process" => self.credential_process = parse_empty(k, v)?,
+ "direct-minimal-versions" => self.direct_minimal_versions = parse_empty(k, v)?,
+ "doctest-xcompile" => self.doctest_xcompile = parse_empty(k, v)?,
+ "dual-proc-macros" => self.dual_proc_macros = parse_empty(k, v)?,
+ "gitoxide" => {
+ self.gitoxide = v.map_or_else(
+ || Ok(Some(GitoxideFeatures::all())),
+ |v| parse_gitoxide(v.split(',')),
+ )?
+ }
+ "host-config" => self.host_config = parse_empty(k, v)?,
"lints" => self.lints = parse_empty(k, v)?,
+ "next-lockfile-bump" => self.next_lockfile_bump = parse_empty(k, v)?,
+ "minimal-versions" => self.minimal_versions = parse_empty(k, v)?,
+ "msrv-policy" => self.msrv_policy = parse_empty(k, v)?,
+ // can also be set in .cargo/config or with and ENV
+ "mtime-on-use" => self.mtime_on_use = parse_empty(k, v)?,
+ "no-index-update" => self.no_index_update = parse_empty(k, v)?,
+ "panic-abort-tests" => self.panic_abort_tests = parse_empty(k, v)?,
+ "profile-rustflags" => self.profile_rustflags = parse_empty(k, v)?,
+ "publish-timeout" => self.publish_timeout = parse_empty(k, v)?,
+ "registry-auth" => self.registry_auth = parse_empty(k, v)?,
+ "rustdoc-map" => self.rustdoc_map = parse_empty(k, v)?,
+ "rustdoc-scrape-examples" => self.rustdoc_scrape_examples = parse_empty(k, v)?,
+ "separate-nightlies" => self.separate_nightlies = parse_empty(k, v)?,
+ "skip-rustdoc-fingerprint" => self.skip_rustdoc_fingerprint = parse_empty(k, v)?,
+ "script" => self.script = parse_empty(k, v)?,
+ "target-applies-to-host" => self.target_applies_to_host = parse_empty(k, v)?,
+ "unstable-options" => self.unstable_options = 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 98498ead8..5d46a7e06 100644
--- a/src/tools/cargo/src/cargo/core/manifest.rs
+++ b/src/tools/cargo/src/cargo/core/manifest.rs
@@ -64,6 +64,7 @@ pub struct Manifest {
metabuild: Option<Vec<String>>,
resolve_behavior: Option<ResolveBehavior>,
lint_rustflags: Vec<String>,
+ embedded: bool,
}
/// When parsing `Cargo.toml`, some warnings should silenced
@@ -407,6 +408,7 @@ impl Manifest {
metabuild: Option<Vec<String>>,
resolve_behavior: Option<ResolveBehavior>,
lint_rustflags: Vec<String>,
+ embedded: bool,
) -> Manifest {
Manifest {
summary,
@@ -433,6 +435,7 @@ impl Manifest {
metabuild,
resolve_behavior,
lint_rustflags,
+ embedded,
}
}
@@ -500,6 +503,9 @@ impl Manifest {
pub fn links(&self) -> Option<&str> {
self.links.as_deref()
}
+ pub fn is_embedded(&self) -> bool {
+ self.embedded
+ }
pub fn workspace_config(&self) -> &WorkspaceConfig {
&self.workspace
diff --git a/src/tools/cargo/src/cargo/core/package.rs b/src/tools/cargo/src/cargo/core/package.rs
index 40ba9cdf8..f4ab448d2 100644
--- a/src/tools/cargo/src/cargo/core/package.rs
+++ b/src/tools/cargo/src/cargo/core/package.rs
@@ -10,10 +10,10 @@ use std::time::{Duration, Instant};
use anyhow::Context;
use bytesize::ByteSize;
-use curl::easy::{Easy, HttpVersion};
+use curl::easy::Easy;
use curl::multi::{EasyHandle, Multi};
use lazycell::LazyCell;
-use log::{debug, warn};
+use log::debug;
use semver::Version;
use serde::Serialize;
@@ -24,10 +24,11 @@ use crate::core::resolver::{HasDevUnits, Resolve};
use crate::core::source::MaybePackage;
use crate::core::{Dependency, Manifest, PackageId, SourceId, Target};
use crate::core::{SourceMap, Summary, Workspace};
-use crate::ops;
use crate::util::config::PackageCacheLock;
use crate::util::errors::{CargoResult, HttpNotSuccessful, DEBUG_HEADERS};
use crate::util::interning::InternedString;
+use crate::util::network::http::http_handle_and_timeout;
+use crate::util::network::http::HttpTimeout;
use crate::util::network::retry::{Retry, RetryResult};
use crate::util::network::sleep::SleepTracker;
use crate::util::{self, internal, Config, Progress, ProgressStyle};
@@ -348,7 +349,7 @@ pub struct Downloads<'a, 'cfg> {
/// Note that timeout management is done manually here instead of in libcurl
/// because we want to apply timeouts to an entire batch of operations, not
/// any one particular single operation.
- timeout: ops::HttpTimeout,
+ timeout: HttpTimeout,
/// Last time bytes were received.
updated_at: Cell<Instant>,
/// This is a slow-speed check. It is reset to `now + timeout_duration`
@@ -441,7 +442,7 @@ impl<'cfg> PackageSet<'cfg> {
pub fn enable_download<'a>(&'a self) -> CargoResult<Downloads<'a, 'cfg>> {
assert!(!self.downloading.replace(true));
- let timeout = ops::HttpTimeout::new(self.config)?;
+ let timeout = HttpTimeout::new(self.config)?;
Ok(Downloads {
start: Instant::now(),
set: self,
@@ -713,7 +714,7 @@ impl<'a, 'cfg> Downloads<'a, 'cfg> {
debug!("downloading {} as {}", id, token);
assert!(self.pending_ids.insert(id));
- let (mut handle, _timeout) = ops::http_handle_and_timeout(self.set.config)?;
+ let (mut handle, _timeout) = http_handle_and_timeout(self.set.config)?;
handle.get(true)?;
handle.url(&url)?;
handle.follow_location(true)?; // follow redirects
@@ -725,32 +726,8 @@ impl<'a, 'cfg> Downloads<'a, 'cfg> {
handle.http_headers(headers)?;
}
- // Enable HTTP/2 to be used as it'll allow true multiplexing which makes
- // downloads much faster.
- //
- // Currently Cargo requests the `http2` feature of the `curl` crate
- // which means it should always be built in. On OSX, however, we ship
- // cargo still linked against the system libcurl. Building curl with
- // ALPN support for HTTP/2 requires newer versions of OSX (the
- // SecureTransport API) than we want to ship Cargo for. By linking Cargo
- // against the system libcurl then older curl installations won't use
- // HTTP/2 but newer ones will. All that to basically say we ignore
- // errors here on OSX, but consider this a fatal error to not activate
- // HTTP/2 on all other platforms.
- if self.set.multiplexing {
- crate::try_old_curl!(handle.http_version(HttpVersion::V2), "HTTP2");
- } else {
- handle.http_version(HttpVersion::V11)?;
- }
-
- // This is an option to `libcurl` which indicates that if there's a
- // bunch of parallel requests to the same host they all wait until the
- // pipelining status of the host is known. This means that we won't
- // initiate dozens of connections to crates.io, but rather only one.
- // Once the main one is opened we realized that pipelining is possible
- // and multiplexing is possible with static.crates.io. All in all this
- // reduces the number of connections down to a more manageable state.
- crate::try_old_curl!(handle.pipewait(true), "pipewait");
+ // Enable HTTP/2 if possible.
+ crate::try_old_curl_http2_pipewait!(self.set.multiplexing, handle);
handle.write_function(move |buf| {
debug!("{} - {} bytes of data", token, buf.len());
diff --git a/src/tools/cargo/src/cargo/core/package_id.rs b/src/tools/cargo/src/cargo/core/package_id.rs
index ee31e9c48..e17a73e68 100644
--- a/src/tools/cargo/src/cargo/core/package_id.rs
+++ b/src/tools/cargo/src/cargo/core/package_id.rs
@@ -5,6 +5,7 @@ use std::hash::Hash;
use std::path::Path;
use std::ptr;
use std::sync::Mutex;
+use std::sync::OnceLock;
use serde::de;
use serde::ser;
@@ -13,10 +14,7 @@ use crate::core::source::SourceId;
use crate::util::interning::InternedString;
use crate::util::{CargoResult, ToSemver};
-lazy_static::lazy_static! {
- static ref PACKAGE_ID_CACHE: Mutex<HashSet<&'static PackageIdInner>> =
- Mutex::new(HashSet::new());
-}
+static PACKAGE_ID_CACHE: OnceLock<Mutex<HashSet<&'static PackageIdInner>>> = OnceLock::new();
/// Identifier for a specific version of a package in a specific source.
#[derive(Clone, Copy, Eq, PartialOrd, Ord)]
@@ -147,7 +145,10 @@ impl PackageId {
version,
source_id,
};
- let mut cache = PACKAGE_ID_CACHE.lock().unwrap();
+ let mut cache = PACKAGE_ID_CACHE
+ .get_or_init(|| Default::default())
+ .lock()
+ .unwrap();
let inner = cache.get(&inner).cloned().unwrap_or_else(|| {
let inner = Box::leak(Box::new(inner));
cache.insert(inner);
@@ -195,6 +196,11 @@ impl PackageId {
pub fn stable_hash(self, workspace: &Path) -> PackageIdStableHash<'_> {
PackageIdStableHash(self, workspace)
}
+
+ /// Filename of the `.crate` tarball, e.g., `once_cell-1.18.0.crate`.
+ pub fn tarball_name(&self) -> String {
+ format!("{}-{}.crate", self.name(), self.version())
+ }
}
pub struct PackageIdStableHash<'a>(PackageId, &'a Path);
diff --git a/src/tools/cargo/src/cargo/core/profiles.rs b/src/tools/cargo/src/cargo/core/profiles.rs
index 3831f18c2..5c7d3e248 100644
--- a/src/tools/cargo/src/cargo/core/profiles.rs
+++ b/src/tools/cargo/src/cargo/core/profiles.rs
@@ -1,4 +1,4 @@
-//! # Profiles: built-in and customizable compiler flag presets
+//! Handles built-in and customizable compiler flag presets.
//!
//! [`Profiles`] is a collections of built-in profiles, and profiles defined
//! in the root manifest and configurations.
@@ -449,9 +449,7 @@ impl ProfileMaker {
// a unit is shared. If that's the case, we'll use the deferred value
// below so the unit can be reused, otherwise we can avoid emitting
// the unit's debuginfo.
- if let Some(debuginfo) = profile.debuginfo.to_option() {
- profile.debuginfo = DebugInfo::Deferred(debuginfo);
- }
+ profile.debuginfo = DebugInfo::Deferred(profile.debuginfo.into_inner());
}
// ... and next comes any other sorts of overrides specified in
// profiles, such as `[profile.release.build-override]` or
@@ -529,7 +527,7 @@ fn merge_profile(profile: &mut Profile, toml: &TomlProfile) {
profile.codegen_units = toml.codegen_units;
}
if let Some(debuginfo) = toml.debug {
- profile.debuginfo = DebugInfo::Explicit(debuginfo);
+ profile.debuginfo = DebugInfo::Resolved(debuginfo);
}
if let Some(debug_assertions) = toml.debug_assertions {
profile.debug_assertions = debug_assertions;
@@ -611,7 +609,7 @@ impl Default for Profile {
lto: Lto::Bool(false),
codegen_backend: None,
codegen_units: None,
- debuginfo: DebugInfo::None,
+ debuginfo: DebugInfo::Resolved(TomlDebugInfo::None),
debug_assertions: false,
split_debuginfo: None,
overflow_checks: false,
@@ -680,7 +678,7 @@ impl Profile {
Profile {
name: InternedString::new("dev"),
root: ProfileRoot::Debug,
- debuginfo: DebugInfo::Explicit(TomlDebugInfo::Full),
+ debuginfo: DebugInfo::Resolved(TomlDebugInfo::Full),
debug_assertions: true,
overflow_checks: true,
incremental: true,
@@ -720,11 +718,8 @@ impl Profile {
/// The debuginfo level setting.
///
-/// This is semantically an `Option<u32>`, and should be used as so via the
-/// [DebugInfo::to_option] method for all intents and purposes:
-/// - `DebugInfo::None` corresponds to `None`
-/// - `DebugInfo::Explicit(u32)` and `DebugInfo::Deferred` correspond to
-/// `Option<u32>::Some`
+/// This is semantically a [`TomlDebugInfo`], and should be used as so via the
+/// [`DebugInfo::into_inner`] method for all intents and purposes.
///
/// Internally, it's used to model a debuginfo level whose value can be deferred
/// for optimization purposes: host dependencies usually don't need the same
@@ -736,35 +731,34 @@ impl Profile {
#[derive(Debug, Copy, Clone, serde::Serialize)]
#[serde(untagged)]
pub enum DebugInfo {
- /// No debuginfo level was set.
- None,
- /// A debuginfo level that is explicitly set, by a profile or a user.
- Explicit(TomlDebugInfo),
+ /// A debuginfo level that is fixed and will not change.
+ ///
+ /// This can be set by a profile, user, or default value.
+ Resolved(TomlDebugInfo),
/// For internal purposes: a deferred debuginfo level that can be optimized
/// away, but has this value otherwise.
///
- /// Behaves like `Explicit` in all situations except for the default build
+ /// Behaves like `Resolved` in all situations except for the default build
/// dependencies profile: whenever a build dependency is not shared with
/// runtime dependencies, this level is weakened to a lower level that is
- /// faster to build (see [DebugInfo::weaken]).
+ /// faster to build (see [`DebugInfo::weaken`]).
///
/// In all other situations, this level value will be the one to use.
Deferred(TomlDebugInfo),
}
impl DebugInfo {
- /// The main way to interact with this debuginfo level, turning it into an Option.
- pub fn to_option(self) -> Option<TomlDebugInfo> {
+ /// The main way to interact with this debuginfo level, turning it into a [`TomlDebugInfo`].
+ pub fn into_inner(self) -> TomlDebugInfo {
match self {
- DebugInfo::None => None,
- DebugInfo::Explicit(v) | DebugInfo::Deferred(v) => Some(v),
+ DebugInfo::Resolved(v) | DebugInfo::Deferred(v) => v,
}
}
/// 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 {
- !matches!(self.to_option(), None | Some(TomlDebugInfo::None))
+ !matches!(self.into_inner(), TomlDebugInfo::None)
}
pub(crate) fn is_deferred(&self) -> bool {
@@ -774,24 +768,20 @@ impl DebugInfo {
/// Force the deferred, preferred, debuginfo level to a finalized explicit value.
pub(crate) fn finalize(self) -> Self {
match self {
- DebugInfo::Deferred(v) => DebugInfo::Explicit(v),
+ DebugInfo::Deferred(v) => DebugInfo::Resolved(v),
_ => self,
}
}
/// Reset to the lowest level: no debuginfo.
- /// If it is explicitly set, keep it explicit.
pub(crate) fn weaken(self) -> Self {
- match self {
- DebugInfo::None => DebugInfo::None,
- _ => DebugInfo::Explicit(TomlDebugInfo::None),
- }
+ DebugInfo::Resolved(TomlDebugInfo::None)
}
}
impl PartialEq for DebugInfo {
fn eq(&self, other: &DebugInfo) -> bool {
- self.to_option().eq(&other.to_option())
+ self.into_inner().eq(&other.into_inner())
}
}
@@ -799,19 +789,19 @@ impl Eq for DebugInfo {}
impl Hash for DebugInfo {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
- self.to_option().hash(state);
+ self.into_inner().hash(state);
}
}
impl PartialOrd for DebugInfo {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
- self.to_option().partial_cmp(&other.to_option())
+ self.into_inner().partial_cmp(&other.into_inner())
}
}
impl Ord for DebugInfo {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
- self.to_option().cmp(&other.to_option())
+ self.into_inner().cmp(&other.into_inner())
}
}
diff --git a/src/tools/cargo/src/cargo/core/resolver/encode.rs b/src/tools/cargo/src/cargo/core/resolver/encode.rs
index 88d0d8296..f73d023b1 100644
--- a/src/tools/cargo/src/cargo/core/resolver/encode.rs
+++ b/src/tools/cargo/src/cargo/core/resolver/encode.rs
@@ -154,10 +154,18 @@ impl EncodableResolve {
/// primary uses is to be used with `resolve_with_previous` to guide the
/// resolver to create a complete Resolve.
pub fn into_resolve(self, original: &str, ws: &Workspace<'_>) -> CargoResult<Resolve> {
+ let unstable_lockfile_version_allowed = ws.config().cli_unstable().next_lockfile_bump;
let path_deps = build_path_deps(ws)?;
let mut checksums = HashMap::new();
let mut version = match self.version {
+ Some(4) if ws.config().nightly_features_allowed => {
+ if unstable_lockfile_version_allowed {
+ ResolveVersion::V4
+ } else {
+ anyhow::bail!("lock file version 4 requires `-Znext-lockfile-bump`");
+ }
+ }
Some(3) => ResolveVersion::V3,
Some(n) => bail!(
"lock file version `{}` was found, but this version of Cargo \
@@ -612,6 +620,7 @@ impl ser::Serialize for Resolve {
metadata,
patch,
version: match self.version() {
+ ResolveVersion::V4 => Some(4),
ResolveVersion::V3 => Some(3),
ResolveVersion::V2 | ResolveVersion::V1 => None,
},
diff --git a/src/tools/cargo/src/cargo/core/resolver/features.rs b/src/tools/cargo/src/cargo/core/resolver/features.rs
index 6b79722ca..3670e8711 100644
--- a/src/tools/cargo/src/cargo/core/resolver/features.rs
+++ b/src/tools/cargo/src/cargo/core/resolver/features.rs
@@ -1,4 +1,4 @@
-//! # Feature resolver
+//! Resolves conditional compilation for [`features` section] in the manifest.
//!
//! This is a [new feature resolver] that runs independently of the main
//! dependency resolver. It has several options which can enable new feature
@@ -34,6 +34,7 @@
//!
//! There are probably other assumptions that I am forgetting.
//!
+//! [`features` section]: https://doc.rust-lang.org/nightly/cargo/reference/features.html
//! [new feature resolver]: https://doc.rust-lang.org/nightly/cargo/reference/resolver.html#feature-resolver-version-2
//! [`resolve_ws_with_opts`]: crate::ops::resolve_ws_with_opts
diff --git a/src/tools/cargo/src/cargo/core/resolver/resolve.rs b/src/tools/cargo/src/cargo/core/resolver/resolve.rs
index 6ab957e92..8405a1245 100644
--- a/src/tools/cargo/src/cargo/core/resolver/resolve.rs
+++ b/src/tools/cargo/src/cargo/core/resolver/resolve.rs
@@ -80,6 +80,10 @@ pub enum ResolveVersion {
/// V3 by default staring in 1.53.
#[default]
V3,
+ /// Unstable. Will collect a certain amount of changes and then go.
+ ///
+ /// Changes made:
+ V4,
}
impl Resolve {
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 002f11ff8..bf26d0498 100644
--- a/src/tools/cargo/src/cargo/core/resolver/version_prefs.rs
+++ b/src/tools/cargo/src/cargo/core/resolver/version_prefs.rs
@@ -81,7 +81,6 @@ impl VersionPreferences {
mod test {
use super::*;
use crate::core::SourceId;
- use crate::util::Config;
use std::collections::BTreeMap;
fn pkgid(name: &str, version: &str) -> PackageId {
@@ -98,10 +97,8 @@ mod test {
fn summ(name: &str, version: &str) -> Summary {
let pkg_id = pkgid(name, version);
- let config = Config::default().unwrap();
let features = BTreeMap::new();
Summary::new(
- &config,
pkg_id,
Vec::new(),
&features,
diff --git a/src/tools/cargo/src/cargo/core/shell.rs b/src/tools/cargo/src/cargo/core/shell.rs
index f74bde257..4d45e6098 100644
--- a/src/tools/cargo/src/cargo/core/shell.rs
+++ b/src/tools/cargo/src/cargo/core/shell.rs
@@ -1,7 +1,7 @@
use std::fmt;
use std::io::prelude::*;
+use std::io::IsTerminal;
-use is_terminal::IsTerminal;
use termcolor::Color::{Cyan, Green, Red, Yellow};
use termcolor::{self, Color, ColorSpec, StandardStream, WriteColor};
diff --git a/src/tools/cargo/src/cargo/core/source/mod.rs b/src/tools/cargo/src/cargo/core/source/mod.rs
index 6ca614d34..2d1db1d53 100644
--- a/src/tools/cargo/src/cargo/core/source/mod.rs
+++ b/src/tools/cargo/src/cargo/core/source/mod.rs
@@ -87,10 +87,25 @@ pub trait Source {
/// If quiet, the source should not display any progress or status messages.
fn set_quiet(&mut self, quiet: bool);
- /// Fetches the full package for each name and version specified.
+ /// Starts the process to fetch a [`Package`] for the given [`PackageId`].
+ ///
+ /// If the source already has the package available on disk, then it
+ /// should return immediately with [`MaybePackage::Ready`] with the
+ /// [`Package`]. Otherwise it should return a [`MaybePackage::Download`]
+ /// to indicate the URL to download the package (this is for remote
+ /// registry sources only).
+ ///
+ /// In the case where [`MaybePackage::Download`] is returned, then the
+ /// package downloader will call [`Source::finish_download`] after the
+ /// download has finished.
fn download(&mut self, package: PackageId) -> CargoResult<MaybePackage>;
- /// Fetches the full package **immediately** for each name and version specified.
+ /// Convenience method used to **immediately** fetch a [`Package`] for the
+ /// given [`PackageId`].
+ ///
+ /// This may trigger a download if necessary. This should only be used
+ /// when a single package is needed (as in the case for `cargo install`).
+ /// Otherwise downloads should be batched together via [`PackageSet`].
fn download_now(self: Box<Self>, package: PackageId, config: &Config) -> CargoResult<Package>
where
Self: std::marker::Sized,
@@ -102,7 +117,13 @@ pub trait Source {
Ok(Package::clone(pkg))
}
- /// Finalizes the download contents of the given [`PackageId`] to a [`Package`].
+ /// Gives the source the downloaded `.crate` file.
+ ///
+ /// When a source has returned [`MaybePackage::Download`] in the
+ /// [`Source::download`] method, then this function will be called with
+ /// the results of the download of the given URL. The source is
+ /// responsible for saving to disk, and returning the appropriate
+ /// [`Package`].
fn finish_download(&mut self, pkg_id: PackageId, contents: Vec<u8>) -> CargoResult<Package>;
/// Generates a unique string which represents the fingerprint of the
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 c369dab16..4064364d5 100644
--- a/src/tools/cargo/src/cargo/core/source/source_id.rs
+++ b/src/tools/cargo/src/cargo/core/source/source_id.rs
@@ -13,11 +13,10 @@ use std::hash::{self, Hash};
use std::path::{Path, PathBuf};
use std::ptr;
use std::sync::Mutex;
+use std::sync::OnceLock;
use url::Url;
-lazy_static::lazy_static! {
- static ref SOURCE_ID_CACHE: Mutex<HashSet<&'static SourceIdInner>> = Default::default();
-}
+static SOURCE_ID_CACHE: OnceLock<Mutex<HashSet<&'static SourceIdInner>>> = OnceLock::new();
/// Unique identifier for a source of packages.
///
@@ -118,7 +117,10 @@ impl SourceId {
/// Interns the value and returns the wrapped type.
fn wrap(inner: SourceIdInner) -> SourceId {
- let mut cache = SOURCE_ID_CACHE.lock().unwrap();
+ let mut cache = SOURCE_ID_CACHE
+ .get_or_init(|| Default::default())
+ .lock()
+ .unwrap();
let inner = cache.get(&inner).cloned().unwrap_or_else(|| {
let inner = Box::leak(Box::new(inner));
cache.insert(inner);
diff --git a/src/tools/cargo/src/cargo/core/summary.rs b/src/tools/cargo/src/cargo/core/summary.rs
index 2535c4482..1883df33b 100644
--- a/src/tools/cargo/src/cargo/core/summary.rs
+++ b/src/tools/cargo/src/cargo/core/summary.rs
@@ -1,6 +1,6 @@
use crate::core::{Dependency, PackageId, SourceId};
use crate::util::interning::InternedString;
-use crate::util::{CargoResult, Config};
+use crate::util::CargoResult;
use anyhow::bail;
use semver::Version;
use std::collections::{BTreeMap, HashMap, HashSet};
@@ -30,7 +30,6 @@ struct Inner {
impl Summary {
pub fn new(
- config: &Config,
pkg_id: PackageId,
dependencies: Vec<Dependency>,
features: &BTreeMap<InternedString, Vec<InternedString>>,
@@ -49,7 +48,7 @@ impl Summary {
)
}
}
- let feature_map = build_feature_map(config, pkg_id, features, &dependencies)?;
+ let feature_map = build_feature_map(pkg_id, features, &dependencies)?;
Ok(Summary {
inner: Rc::new(Inner {
package_id: pkg_id,
@@ -140,7 +139,6 @@ impl Hash for Summary {
/// Checks features for errors, bailing out a CargoResult:Err if invalid,
/// and creates FeatureValues for each feature.
fn build_feature_map(
- config: &Config,
pkg_id: PackageId,
features: &BTreeMap<InternedString, Vec<InternedString>>,
dependencies: &[Dependency],
@@ -204,7 +202,7 @@ fn build_feature_map(
feature
);
}
- validate_feature_name(config, pkg_id, feature)?;
+ validate_feature_name(pkg_id, feature)?;
for fv in fvs {
// Find data for the referenced dependency...
let dep_data = {
@@ -431,33 +429,63 @@ impl fmt::Display for FeatureValue {
pub type FeatureMap = BTreeMap<InternedString, Vec<FeatureValue>>;
-fn validate_feature_name(config: &Config, pkg_id: PackageId, name: &str) -> CargoResult<()> {
+fn validate_feature_name(pkg_id: PackageId, name: &str) -> CargoResult<()> {
let mut chars = name.chars();
- const FUTURE: &str = "This was previously accepted but is being phased out; \
- it will become a hard error in a future release.\n\
- For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, \
- and please leave a comment if this will be a problem for your project.";
if let Some(ch) = chars.next() {
if !(unicode_xid::UnicodeXID::is_xid_start(ch) || ch == '_' || ch.is_digit(10)) {
- config.shell().warn(&format!(
+ bail!(
"invalid character `{}` in feature `{}` in package {}, \
the first character must be a Unicode XID start character or digit \
- (most letters or `_` or `0` to `9`)\n\
- {}",
- ch, name, pkg_id, FUTURE
- ))?;
+ (most letters or `_` or `0` to `9`)",
+ ch,
+ name,
+ pkg_id
+ );
}
}
for ch in chars {
if !(unicode_xid::UnicodeXID::is_xid_continue(ch) || ch == '-' || ch == '+' || ch == '.') {
- config.shell().warn(&format!(
+ bail!(
"invalid character `{}` in feature `{}` in package {}, \
characters must be Unicode XID characters, `+`, or `.` \
- (numbers, `+`, `-`, `_`, `.`, or most letters)\n\
- {}",
- ch, name, pkg_id, FUTURE
- ))?;
+ (numbers, `+`, `-`, `_`, `.`, or most letters)",
+ ch,
+ name,
+ pkg_id
+ );
}
}
Ok(())
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::sources::CRATES_IO_INDEX;
+ use crate::util::into_url::IntoUrl;
+
+ use crate::core::SourceId;
+
+ #[test]
+ fn valid_feature_names() {
+ let loc = CRATES_IO_INDEX.into_url().unwrap();
+ let source_id = SourceId::for_registry(&loc).unwrap();
+ let pkg_id = PackageId::new("foo", "1.0.0", source_id).unwrap();
+
+ assert!(validate_feature_name(pkg_id, "c++17").is_ok());
+ assert!(validate_feature_name(pkg_id, "128bit").is_ok());
+ assert!(validate_feature_name(pkg_id, "_foo").is_ok());
+ assert!(validate_feature_name(pkg_id, "feat-name").is_ok());
+ assert!(validate_feature_name(pkg_id, "feat_name").is_ok());
+ assert!(validate_feature_name(pkg_id, "foo.bar").is_ok());
+
+ assert!(validate_feature_name(pkg_id, "+foo").is_err());
+ assert!(validate_feature_name(pkg_id, "-foo").is_err());
+ assert!(validate_feature_name(pkg_id, ".foo").is_err());
+ assert!(validate_feature_name(pkg_id, "foo:bar").is_err());
+ assert!(validate_feature_name(pkg_id, "foo?").is_err());
+ assert!(validate_feature_name(pkg_id, "?foo").is_err());
+ assert!(validate_feature_name(pkg_id, "ⒶⒷⒸ").is_err());
+ assert!(validate_feature_name(pkg_id, "a¼").is_err());
+ }
+}
diff --git a/src/tools/cargo/src/cargo/core/workspace.rs b/src/tools/cargo/src/cargo/core/workspace.rs
index 9922d6d33..db9c18010 100644
--- a/src/tools/cargo/src/cargo/core/workspace.rs
+++ b/src/tools/cargo/src/cargo/core/workspace.rs
@@ -15,7 +15,7 @@ use crate::core::features::Features;
use crate::core::registry::PackageRegistry;
use crate::core::resolver::features::CliFeatures;
use crate::core::resolver::ResolveBehavior;
-use crate::core::{Dependency, FeatureValue, PackageId, PackageIdSpec};
+use crate::core::{Dependency, Edition, FeatureValue, PackageId, PackageIdSpec};
use crate::core::{EitherManifest, Package, SourceId, VirtualManifest};
use crate::ops;
use crate::sources::{PathSource, CRATES_IO_INDEX, CRATES_IO_REGISTRY};
@@ -381,7 +381,21 @@ impl<'cfg> Workspace<'cfg> {
pub fn target_dir(&self) -> Filesystem {
self.target_dir
.clone()
- .unwrap_or_else(|| Filesystem::new(self.root().join("target")))
+ .unwrap_or_else(|| self.default_target_dir())
+ }
+
+ fn default_target_dir(&self) -> Filesystem {
+ if self.root_maybe().is_embedded() {
+ let hash = crate::util::hex::short_hash(&self.root_manifest().to_string_lossy());
+ let mut rel_path = PathBuf::new();
+ rel_path.push("target");
+ rel_path.push(&hash[0..2]);
+ rel_path.push(&hash[2..]);
+
+ self.config().home().join(rel_path)
+ } else {
+ Filesystem::new(self.root().join("target"))
+ }
}
/// Returns the root `[replace]` section of this workspace.
@@ -726,6 +740,10 @@ impl<'cfg> Workspace<'cfg> {
if self.members.contains(&manifest_path) {
return Ok(());
}
+ if is_path_dep && self.root_maybe().is_embedded() {
+ // Embedded manifests cannot have workspace members
+ return Ok(());
+ }
if is_path_dep
&& !manifest_path.parent().unwrap().starts_with(self.root())
&& self.find_root(&manifest_path)? != self.root_manifest
@@ -993,6 +1011,24 @@ impl<'cfg> Workspace<'cfg> {
}
}
}
+ if let MaybePackage::Virtual(vm) = self.root_maybe() {
+ if vm.resolve_behavior().is_none() {
+ if let Some(edition) = self
+ .members()
+ .filter(|p| p.manifest_path() != root_manifest)
+ .map(|p| p.manifest().edition())
+ .filter(|&e| e >= Edition::Edition2021)
+ .max()
+ {
+ let resolver = edition.default_resolve_behavior().to_manifest();
+ self.config.shell().warn(format_args!("some crates are on edition {edition} which defaults to `resolver = \"{resolver}\"`, but virtual workspaces default to `resolver = \"1\"`"))?;
+ self.config.shell().note(
+ "to keep the current resolver, specify `workspace.resolver = \"1\"` in the workspace root's manifest",
+ )?;
+ self.config.shell().note(format_args!("to use the edition {edition} resolver, specify `workspace.resolver = \"{resolver}\"` in the workspace root's manifest"))?;
+ }
+ }
+ }
}
Ok(())
}
@@ -1562,6 +1598,14 @@ impl MaybePackage {
MaybePackage::Virtual(ref vm) => vm.workspace_config(),
}
}
+
+ /// Has an embedded manifest (single-file package)
+ pub fn is_embedded(&self) -> bool {
+ match self {
+ MaybePackage::Package(p) => p.manifest().is_embedded(),
+ MaybePackage::Virtual(_) => false,
+ }
+ }
}
impl WorkspaceRootConfig {
diff --git a/src/tools/cargo/src/cargo/lib.rs b/src/tools/cargo/src/cargo/lib.rs
index 31d03ad25..a03d51199 100644
--- a/src/tools/cargo/src/cargo/lib.rs
+++ b/src/tools/cargo/src/cargo/lib.rs
@@ -6,6 +6,9 @@
#![allow(clippy::all)]
#![warn(clippy::disallowed_methods)]
#![warn(clippy::self_named_module_files)]
+#![warn(clippy::print_stdout)]
+#![warn(clippy::print_stderr)]
+#![warn(clippy::dbg_macro)]
#![allow(rustdoc::private_intra_doc_links)]
//! # Cargo as a library
diff --git a/src/tools/cargo/src/cargo/ops/cargo_clean.rs b/src/tools/cargo/src/cargo/ops/cargo_clean.rs
index de3139c99..b9b33690e 100644
--- a/src/tools/cargo/src/cargo/ops/cargo_clean.rs
+++ b/src/tools/cargo/src/cargo/ops/cargo_clean.rs
@@ -297,7 +297,12 @@ fn rm_rf(path: &Path, config: &Config, progress: &mut dyn CleaningProgressBar) -
let entry = entry?;
progress.on_clean()?;
if entry.file_type().is_dir() {
- paths::remove_dir(entry.path()).with_context(|| "could not remove build directory")?;
+ // The contents should have been removed by now, but sometimes a race condition is hit
+ // where other files have been added by the OS. `paths::remove_dir_all` also falls back
+ // to `std::fs::remove_dir_all`, which may be more reliable than a simple walk in
+ // platform-specific edge cases.
+ paths::remove_dir_all(entry.path())
+ .with_context(|| "could not remove build directory")?;
} else {
paths::remove_file(entry.path()).with_context(|| "failed to remove build artifact")?;
}
diff --git a/src/tools/cargo/src/cargo/ops/cargo_compile/mod.rs b/src/tools/cargo/src/cargo/ops/cargo_compile/mod.rs
index 3b6043d4f..f53a9e934 100644
--- a/src/tools/cargo/src/cargo/ops/cargo_compile/mod.rs
+++ b/src/tools/cargo/src/cargo/ops/cargo_compile/mod.rs
@@ -1,7 +1,5 @@
-//! # The Cargo "compile" operation
-//!
-//! This module contains the entry point for starting the compilation process
-//! for commands like `build`, `test`, `doc`, `rustc`, etc.
+//! The entry point for starting the compilation process for commands like
+//! `build`, `test`, `doc`, `rustc`, etc.
//!
//! The [`compile`] function will do all the work to compile a workspace. A
//! rough outline is:
diff --git a/src/tools/cargo/src/cargo/ops/cargo_fetch.rs b/src/tools/cargo/src/cargo/ops/cargo_fetch.rs
index bac3f0278..273bce284 100644
--- a/src/tools/cargo/src/cargo/ops/cargo_fetch.rs
+++ b/src/tools/cargo/src/cargo/ops/cargo_fetch.rs
@@ -2,6 +2,7 @@ use crate::core::compiler::standard_lib;
use crate::core::compiler::{BuildConfig, CompileMode, RustcTargetData};
use crate::core::{PackageSet, Resolve, Workspace};
use crate::ops;
+use crate::util::config::JobsConfig;
use crate::util::CargoResult;
use crate::util::Config;
use std::collections::HashSet;
@@ -20,7 +21,7 @@ pub fn fetch<'a>(
ws.emit_warnings()?;
let (mut packages, resolve) = ops::resolve_ws(ws)?;
- let jobs = Some(1);
+ let jobs = Some(JobsConfig::Integer(1));
let keep_going = false;
let config = ws.config();
let build_config = BuildConfig::new(
diff --git a/src/tools/cargo/src/cargo/ops/cargo_install.rs b/src/tools/cargo/src/cargo/ops/cargo_install.rs
index 5f843e8c7..8ddfa4fab 100644
--- a/src/tools/cargo/src/cargo/ops/cargo_install.rs
+++ b/src/tools/cargo/src/cargo/ops/cargo_install.rs
@@ -320,7 +320,9 @@ impl<'cfg, 'a> InstallablePackage<'cfg, 'a> {
format!(
"failed to compile `{}`, intermediate artifacts can be \
- found at `{}`",
+ found at `{}`.\nTo reuse those artifacts with a future \
+ compilation, set the environment variable \
+ `CARGO_TARGET_DIR` to that path.",
self.pkg,
self.ws.target_dir().display()
)
diff --git a/src/tools/cargo/src/cargo/ops/cargo_new.rs b/src/tools/cargo/src/cargo/ops/cargo_new.rs
index 697798c0c..b113671b0 100644
--- a/src/tools/cargo/src/cargo/ops/cargo_new.rs
+++ b/src/tools/cargo/src/cargo/ops/cargo_new.rs
@@ -163,6 +163,7 @@ fn get_name<'a>(path: &'a Path, opts: &'a NewOptions) -> CargoResult<&'a str> {
})
}
+/// See also `util::toml::embedded::sanitize_name`
fn check_name(
name: &str,
show_name_help: bool,
@@ -820,6 +821,18 @@ fn mk(config: &Config, opts: &MkOptions<'_>) -> CargoResult<()> {
workspace_package_keys,
)
}
+
+ // Try to inherit the workspace lints key if it exists.
+ if config.cli_unstable().lints
+ && workspace_document
+ .get("workspace")
+ .and_then(|workspace| workspace.get("lints"))
+ .is_some()
+ {
+ let mut table = toml_edit::Table::new();
+ table["workspace"] = toml_edit::value(true);
+ manifest["lints"] = toml_edit::Item::Table(table);
+ }
}
}
diff --git a/src/tools/cargo/src/cargo/ops/cargo_package.rs b/src/tools/cargo/src/cargo/ops/cargo_package.rs
index f80848c75..a322afbb3 100644
--- a/src/tools/cargo/src/cargo/ops/cargo_package.rs
+++ b/src/tools/cargo/src/cargo/ops/cargo_package.rs
@@ -13,6 +13,7 @@ use crate::core::{registry::PackageRegistry, resolver::HasDevUnits};
use crate::core::{Feature, Shell, Verbosity, Workspace};
use crate::core::{Package, PackageId, PackageSet, Resolve, SourceId};
use crate::sources::PathSource;
+use crate::util::config::JobsConfig;
use crate::util::errors::CargoResult;
use crate::util::toml::TomlManifest;
use crate::util::{self, human_readable_bytes, restricted_names, Config, FileLock};
@@ -31,7 +32,7 @@ pub struct PackageOpts<'cfg> {
pub check_metadata: bool,
pub allow_dirty: bool,
pub verify: bool,
- pub jobs: Option<i32>,
+ pub jobs: Option<JobsConfig>,
pub keep_going: bool,
pub to_package: ops::Packages,
pub targets: Vec<String>,
@@ -126,7 +127,7 @@ pub fn package_one(
super::check_dep_has_version(dep, false)?;
}
- let filename = format!("{}-{}.crate", pkg.name(), pkg.version());
+ let filename = pkg.package_id().tarball_name();
let dir = ws.target_dir().join("package");
let mut dst = {
let tmp = format!(".{}", filename);
@@ -198,7 +199,7 @@ pub fn package(ws: &Workspace<'_>, opts: &PackageOpts<'_>) -> CargoResult<Option
check_metadata: opts.check_metadata,
allow_dirty: opts.allow_dirty,
verify: opts.verify,
- jobs: opts.jobs,
+ jobs: opts.jobs.clone(),
keep_going: opts.keep_going,
to_package: ops::Packages::Default,
targets: opts.targets.clone(),
@@ -392,7 +393,7 @@ fn build_lock(ws: &Workspace<'_>, orig_pkg: &Package) -> CargoResult<String> {
let package_root = orig_pkg.root();
let source_id = orig_pkg.package_id().source_id();
let (manifest, _nested_paths) =
- TomlManifest::to_real_manifest(&toml_manifest, source_id, package_root, config)?;
+ TomlManifest::to_real_manifest(&toml_manifest, false, source_id, package_root, config)?;
let new_pkg = Package::new(manifest, orig_pkg.manifest_path());
// Regenerate Cargo.lock using the old one as a guide.
@@ -861,7 +862,7 @@ fn run_verify(
&ops::CompileOptions {
build_config: BuildConfig::new(
config,
- opts.jobs,
+ opts.jobs.clone(),
opts.keep_going,
&opts.targets,
CompileMode::Build,
diff --git a/src/tools/cargo/src/cargo/ops/cargo_test.rs b/src/tools/cargo/src/cargo/ops/cargo_test.rs
index b7e61982d..1ddf7755f 100644
--- a/src/tools/cargo/src/cargo/ops/cargo_test.rs
+++ b/src/tools/cargo/src/cargo/ops/cargo_test.rs
@@ -172,7 +172,6 @@ fn run_doc_tests(
let config = ws.config();
let mut errors = Vec::new();
let doctest_xcompile = config.cli_unstable().doctest_xcompile;
- let doctest_in_workspace = config.cli_unstable().doctest_in_workspace;
for doctest_info in &compilation.to_doc_test {
let Doctest {
@@ -215,15 +214,9 @@ fn run_doc_tests(
p.arg("--crate-name").arg(&unit.target.crate_name());
p.arg("--test");
- if doctest_in_workspace {
- add_path_args(ws, unit, &mut p);
- // FIXME(swatinem): remove the `unstable-options` once rustdoc stabilizes the `test-run-directory` option
- p.arg("-Z").arg("unstable-options");
- p.arg("--test-run-directory")
- .arg(unit.pkg.root().to_path_buf());
- } else {
- p.arg(unit.target.src_path().path().unwrap());
- }
+ add_path_args(ws, unit, &mut p);
+ p.arg("--test-run-directory")
+ .arg(unit.pkg.root().to_path_buf());
if let CompileKind::Target(target) = unit.kind {
// use `rustc_target()` to properly handle JSON target paths
diff --git a/src/tools/cargo/src/cargo/ops/lockfile.rs b/src/tools/cargo/src/cargo/ops/lockfile.rs
index e11e492af..b27a7e742 100644
--- a/src/tools/cargo/src/cargo/ops/lockfile.rs
+++ b/src/tools/cargo/src/cargo/ops/lockfile.rs
@@ -8,12 +8,12 @@ use crate::util::Filesystem;
use anyhow::Context as _;
pub fn load_pkg_lockfile(ws: &Workspace<'_>) -> CargoResult<Option<Resolve>> {
- if !ws.root().join("Cargo.lock").exists() {
+ let lock_root = lock_root(ws);
+ if !lock_root.as_path_unlocked().join("Cargo.lock").exists() {
return Ok(None);
}
- let root = Filesystem::new(ws.root().to_path_buf());
- let mut f = root.open_ro("Cargo.lock", ws.config(), "Cargo.lock file")?;
+ let mut f = lock_root.open_ro("Cargo.lock", ws.config(), "Cargo.lock file")?;
let mut s = String::new();
f.read_to_string(&mut s)
@@ -30,12 +30,12 @@ pub fn load_pkg_lockfile(ws: &Workspace<'_>) -> CargoResult<Option<Resolve>> {
/// Generate a toml String of Cargo.lock from a Resolve.
pub fn resolve_to_string(ws: &Workspace<'_>, resolve: &mut Resolve) -> CargoResult<String> {
- let (_orig, out, _ws_root) = resolve_to_string_orig(ws, resolve);
+ let (_orig, out, _lock_root) = resolve_to_string_orig(ws, resolve);
Ok(out)
}
pub fn write_pkg_lockfile(ws: &Workspace<'_>, resolve: &mut Resolve) -> CargoResult<()> {
- let (orig, mut out, ws_root) = resolve_to_string_orig(ws, resolve);
+ let (orig, mut out, lock_root) = resolve_to_string_orig(ws, resolve);
// If the lock file contents haven't changed so don't rewrite it. This is
// helpful on read-only filesystems.
@@ -55,7 +55,7 @@ pub fn write_pkg_lockfile(ws: &Workspace<'_>, resolve: &mut Resolve) -> CargoRes
"the lock file {} needs to be updated but {} was passed to prevent this\n\
If you want to try to generate the lock file without accessing the network, \
remove the {} flag and use --offline instead.",
- ws.root().to_path_buf().join("Cargo.lock").display(),
+ lock_root.as_path_unlocked().join("Cargo.lock").display(),
flag,
flag
);
@@ -69,17 +69,30 @@ pub fn write_pkg_lockfile(ws: &Workspace<'_>, resolve: &mut Resolve) -> CargoRes
if resolve.version() < ResolveVersion::default() {
resolve.set_version(ResolveVersion::default());
out = serialize_resolve(resolve, orig.as_deref());
+ } else if resolve.version() > ResolveVersion::default()
+ && !ws.config().cli_unstable().next_lockfile_bump
+ {
+ // The next version hasn't yet stabilized.
+ anyhow::bail!(
+ "lock file version `{:?}` requires `-Znext-lockfile-bump`",
+ resolve.version()
+ )
}
// Ok, if that didn't work just write it out
- ws_root
+ lock_root
.open_rw("Cargo.lock", ws.config(), "Cargo.lock file")
.and_then(|mut f| {
f.file().set_len(0)?;
f.write_all(out.as_bytes())?;
Ok(())
})
- .with_context(|| format!("failed to write {}", ws.root().join("Cargo.lock").display()))?;
+ .with_context(|| {
+ format!(
+ "failed to write {}",
+ lock_root.as_path_unlocked().join("Cargo.lock").display()
+ )
+ })?;
Ok(())
}
@@ -88,15 +101,15 @@ fn resolve_to_string_orig(
resolve: &mut Resolve,
) -> (Option<String>, String, Filesystem) {
// Load the original lock file if it exists.
- let ws_root = Filesystem::new(ws.root().to_path_buf());
- let orig = ws_root.open_ro("Cargo.lock", ws.config(), "Cargo.lock file");
+ let lock_root = lock_root(ws);
+ let orig = lock_root.open_ro("Cargo.lock", ws.config(), "Cargo.lock file");
let orig = orig.and_then(|mut f| {
let mut s = String::new();
f.read_to_string(&mut s)?;
Ok(s)
});
let out = serialize_resolve(resolve, orig.as_deref().ok());
- (orig.ok(), out, ws_root)
+ (orig.ok(), out, lock_root)
}
fn serialize_resolve(resolve: &Resolve, orig: Option<&str>) -> String {
@@ -227,3 +240,11 @@ fn emit_package(dep: &toml::Table, out: &mut String) {
out.push_str(&format!("replace = {}\n\n", &dep["replace"]));
}
}
+
+fn lock_root(ws: &Workspace<'_>) -> Filesystem {
+ if ws.root_maybe().is_embedded() {
+ ws.target_dir()
+ } else {
+ Filesystem::new(ws.root().to_owned())
+ }
+}
diff --git a/src/tools/cargo/src/cargo/ops/mod.rs b/src/tools/cargo/src/cargo/ops/mod.rs
index 4b6aea991..d4ec442dd 100644
--- a/src/tools/cargo/src/cargo/ops/mod.rs
+++ b/src/tools/cargo/src/cargo/ops/mod.rs
@@ -21,11 +21,15 @@ pub use self::cargo_test::{run_benches, run_tests, TestOptions};
pub use self::cargo_uninstall::uninstall;
pub use self::fix::{fix, fix_exec_rustc, fix_get_proxy_lock_addr, FixOptions};
pub use self::lockfile::{load_pkg_lockfile, resolve_to_string, write_pkg_lockfile};
-pub use self::registry::HttpTimeout;
-pub use self::registry::{configure_http_handle, http_handle, http_handle_and_timeout};
-pub use self::registry::{modify_owners, yank, OwnersOptions, PublishOpts};
-pub use self::registry::{needs_custom_http_transport, registry_login, registry_logout, search};
-pub use self::registry::{publish, RegistryCredentialConfig};
+pub use self::registry::modify_owners;
+pub use self::registry::publish;
+pub use self::registry::registry_login;
+pub use self::registry::registry_logout;
+pub use self::registry::search;
+pub use self::registry::yank;
+pub use self::registry::OwnersOptions;
+pub use self::registry::PublishOpts;
+pub use self::registry::RegistryCredentialConfig;
pub use self::resolve::{
add_overrides, get_resolved_packages, resolve_with_previous, resolve_ws, resolve_ws_with_opts,
WorkspaceResolve,
diff --git a/src/tools/cargo/src/cargo/ops/registry.rs b/src/tools/cargo/src/cargo/ops/registry.rs
deleted file mode 100644
index a8efb5492..000000000
--- a/src/tools/cargo/src/cargo/ops/registry.rs
+++ /dev/null
@@ -1,1227 +0,0 @@
-use std::cmp;
-use std::collections::{BTreeMap, HashSet};
-use std::fs::File;
-use std::io::{self, BufRead};
-use std::iter::repeat;
-use std::path::PathBuf;
-use std::str;
-use std::task::Poll;
-use std::time::Duration;
-
-use anyhow::{anyhow, bail, format_err, Context as _};
-use cargo_util::paths;
-use crates_io::{self, NewCrate, NewCrateDependency, Registry};
-use curl::easy::{Easy, InfoType, SslOpt, SslVersion};
-use log::{log, Level};
-use pasetors::keys::{AsymmetricKeyPair, Generate};
-use pasetors::paserk::FormatAsPaserk;
-use termcolor::Color::Green;
-use termcolor::ColorSpec;
-use url::Url;
-
-use crate::core::dependency::DepKind;
-use crate::core::dependency::Dependency;
-use crate::core::manifest::ManifestMetadata;
-use crate::core::resolver::CliFeatures;
-use crate::core::source::Source;
-use crate::core::QueryKind;
-use crate::core::{Package, SourceId, Workspace};
-use crate::ops;
-use crate::ops::Packages;
-use crate::sources::{RegistrySource, SourceConfigMap, CRATES_IO_DOMAIN, CRATES_IO_REGISTRY};
-use crate::util::auth::{
- paserk_public_from_paserk_secret, Secret, {self, AuthorizationError},
-};
-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};
-
-/// Registry settings loaded from config files.
-///
-/// This is loaded based on the `--registry` flag and the config settings.
-#[derive(Debug, PartialEq)]
-pub enum RegistryCredentialConfig {
- None,
- /// The authentication token.
- Token(Secret<String>),
- /// Process used for fetching a token.
- Process((PathBuf, Vec<String>)),
- /// Secret Key and subject for Asymmetric tokens.
- AsymmetricKey((Secret<String>, Option<String>)),
-}
-
-impl RegistryCredentialConfig {
- /// Returns `true` if the credential is [`None`].
- ///
- /// [`None`]: Self::None
- pub fn is_none(&self) -> bool {
- matches!(self, Self::None)
- }
- /// Returns `true` if the credential is [`Token`].
- ///
- /// [`Token`]: Self::Token
- pub fn is_token(&self) -> bool {
- matches!(self, Self::Token(..))
- }
- /// Returns `true` if the credential is [`AsymmetricKey`].
- ///
- /// [`AsymmetricKey`]: RegistryCredentialConfig::AsymmetricKey
- pub fn is_asymmetric_key(&self) -> bool {
- matches!(self, Self::AsymmetricKey(..))
- }
- pub fn as_token(&self) -> Option<Secret<&str>> {
- if let Self::Token(v) = self {
- Some(v.as_deref())
- } else {
- None
- }
- }
- pub fn as_process(&self) -> Option<&(PathBuf, Vec<String>)> {
- if let Self::Process(v) = self {
- Some(v)
- } else {
- None
- }
- }
- pub fn as_asymmetric_key(&self) -> Option<&(Secret<String>, Option<String>)> {
- if let Self::AsymmetricKey(v) = self {
- Some(v)
- } else {
- None
- }
- }
-}
-
-pub struct PublishOpts<'cfg> {
- pub config: &'cfg Config,
- pub token: Option<Secret<String>>,
- pub index: Option<String>,
- pub verify: bool,
- pub allow_dirty: bool,
- pub jobs: Option<i32>,
- pub keep_going: bool,
- pub to_publish: ops::Packages,
- pub targets: Vec<String>,
- pub dry_run: bool,
- pub registry: Option<String>,
- pub cli_features: CliFeatures,
-}
-
-pub fn publish(ws: &Workspace<'_>, opts: &PublishOpts<'_>) -> CargoResult<()> {
- let specs = opts.to_publish.to_package_id_specs(ws)?;
- if specs.len() > 1 {
- bail!("the `-p` argument must be specified to select a single package to publish")
- }
- if Packages::Default == opts.to_publish && ws.is_virtual() {
- bail!("the `-p` argument must be specified in the root of a virtual workspace")
- }
- let member_ids = ws.members().map(|p| p.package_id());
- // Check that the spec matches exactly one member.
- specs[0].query(member_ids)?;
- let mut pkgs = ws.members_with_features(&specs, &opts.cli_features)?;
- // In `members_with_features_old`, it will add "current" package (determined by the cwd)
- // So we need filter
- pkgs = pkgs
- .into_iter()
- .filter(|(m, _)| specs.iter().any(|spec| spec.matches(m.package_id())))
- .collect();
- // Double check. It is safe theoretically, unless logic has updated.
- assert_eq!(pkgs.len(), 1);
-
- let (pkg, cli_features) = pkgs.pop().unwrap();
-
- let mut publish_registry = opts.registry.clone();
- if let Some(ref allowed_registries) = *pkg.publish() {
- if publish_registry.is_none() && allowed_registries.len() == 1 {
- // If there is only one allowed registry, push to that one directly,
- // even though there is no registry specified in the command.
- let default_registry = &allowed_registries[0];
- if default_registry != CRATES_IO_REGISTRY {
- // Don't change the registry for crates.io and don't warn the user.
- // crates.io will be defaulted even without this.
- opts.config.shell().note(&format!(
- "Found `{}` as only allowed registry. Publishing to it automatically.",
- default_registry
- ))?;
- publish_registry = Some(default_registry.clone());
- }
- }
-
- let reg_name = publish_registry
- .clone()
- .unwrap_or_else(|| CRATES_IO_REGISTRY.to_string());
- if allowed_registries.is_empty() {
- bail!(
- "`{}` cannot be published.\n\
- `package.publish` is set to `false` or an empty list in Cargo.toml and prevents publishing.",
- pkg.name(),
- );
- } else if !allowed_registries.contains(&reg_name) {
- bail!(
- "`{}` cannot be published.\n\
- The registry `{}` is not listed in the `package.publish` value in Cargo.toml.",
- pkg.name(),
- reg_name
- );
- }
- }
- // This is only used to confirm that we can create a token before we build the package.
- // This causes the credential provider to be called an extra time, but keeps the same order of errors.
- let ver = pkg.version().to_string();
- let mutation = auth::Mutation::PrePublish;
-
- let (mut registry, reg_ids) = registry(
- opts.config,
- opts.token.as_ref().map(Secret::as_deref),
- opts.index.as_deref(),
- publish_registry.as_deref(),
- true,
- Some(mutation).filter(|_| !opts.dry_run),
- )?;
- verify_dependencies(pkg, &registry, reg_ids.original)?;
-
- // Prepare a tarball, with a non-suppressible warning if metadata
- // is missing since this is being put online.
- let tarball = ops::package_one(
- ws,
- pkg,
- &ops::PackageOpts {
- config: opts.config,
- verify: opts.verify,
- list: false,
- check_metadata: true,
- allow_dirty: opts.allow_dirty,
- to_package: ops::Packages::Default,
- targets: opts.targets.clone(),
- jobs: opts.jobs,
- keep_going: opts.keep_going,
- cli_features: cli_features,
- },
- )?
- .unwrap();
-
- if !opts.dry_run {
- let hash = cargo_util::Sha256::new()
- .update_file(tarball.file())?
- .finish_hex();
- let mutation = Some(auth::Mutation::Publish {
- name: pkg.name().as_str(),
- vers: &ver,
- cksum: &hash,
- });
- registry.set_token(Some(auth::auth_token(
- &opts.config,
- &reg_ids.original,
- None,
- mutation,
- )?));
- }
-
- opts.config
- .shell()
- .status("Uploading", pkg.package_id().to_string())?;
- transmit(
- opts.config,
- pkg,
- tarball.file(),
- &mut registry,
- reg_ids.original,
- opts.dry_run,
- )?;
- if !opts.dry_run {
- const DEFAULT_TIMEOUT: u64 = 60;
- let timeout = if opts.config.cli_unstable().publish_timeout {
- let timeout: Option<u64> = opts.config.get("publish.timeout")?;
- timeout.unwrap_or(DEFAULT_TIMEOUT)
- } else {
- DEFAULT_TIMEOUT
- };
- if 0 < timeout {
- let timeout = std::time::Duration::from_secs(timeout);
- wait_for_publish(opts.config, reg_ids.original, pkg, timeout)?;
- }
- }
-
- Ok(())
-}
-
-fn verify_dependencies(
- pkg: &Package,
- registry: &Registry,
- registry_src: SourceId,
-) -> CargoResult<()> {
- for dep in pkg.dependencies().iter() {
- if super::check_dep_has_version(dep, true)? {
- continue;
- }
- // TomlManifest::prepare_for_publish will rewrite the dependency
- // to be just the `version` field.
- if dep.source_id() != registry_src {
- if !dep.source_id().is_registry() {
- // Consider making SourceId::kind a public type that we can
- // exhaustively match on. Using match can help ensure that
- // every kind is properly handled.
- panic!("unexpected source kind for dependency {:?}", dep);
- }
- // Block requests to send to crates.io with alt-registry deps.
- // This extra hostname check is mostly to assist with testing,
- // but also prevents someone using `--index` to specify
- // something that points to crates.io.
- if registry_src.is_crates_io() || registry.host_is_crates_io() {
- bail!("crates cannot be published to crates.io with dependencies sourced from other\n\
- registries. `{}` needs to be published to crates.io before publishing this crate.\n\
- (crate `{}` is pulled from {})",
- dep.package_name(),
- dep.package_name(),
- dep.source_id());
- }
- }
- }
- Ok(())
-}
-
-fn transmit(
- config: &Config,
- pkg: &Package,
- tarball: &File,
- registry: &mut Registry,
- registry_id: SourceId,
- dry_run: bool,
-) -> CargoResult<()> {
- let deps = pkg
- .dependencies()
- .iter()
- .filter(|dep| {
- // Skip dev-dependency without version.
- dep.is_transitive() || dep.specified_req()
- })
- .map(|dep| {
- // If the dependency is from a different registry, then include the
- // registry in the dependency.
- let dep_registry_id = match dep.registry_id() {
- Some(id) => id,
- None => SourceId::crates_io(config)?,
- };
- // In the index and Web API, None means "from the same registry"
- // whereas in Cargo.toml, it means "from crates.io".
- let dep_registry = if dep_registry_id != registry_id {
- Some(dep_registry_id.url().to_string())
- } else {
- None
- };
-
- Ok(NewCrateDependency {
- optional: dep.is_optional(),
- default_features: dep.uses_default_features(),
- name: dep.package_name().to_string(),
- features: dep.features().iter().map(|s| s.to_string()).collect(),
- version_req: dep.version_req().to_string(),
- target: dep.platform().map(|s| s.to_string()),
- kind: match dep.kind() {
- DepKind::Normal => "normal",
- DepKind::Build => "build",
- DepKind::Development => "dev",
- }
- .to_string(),
- registry: dep_registry,
- explicit_name_in_toml: dep.explicit_name_in_toml().map(|s| s.to_string()),
- })
- })
- .collect::<CargoResult<Vec<NewCrateDependency>>>()?;
- let manifest = pkg.manifest();
- let ManifestMetadata {
- ref authors,
- ref description,
- ref homepage,
- ref documentation,
- ref keywords,
- ref readme,
- ref repository,
- ref license,
- ref license_file,
- ref categories,
- ref badges,
- ref links,
- ref rust_version,
- } = *manifest.metadata();
- let readme_content = readme
- .as_ref()
- .map(|readme| {
- paths::read(&pkg.root().join(readme))
- .with_context(|| format!("failed to read `readme` file for package `{}`", pkg))
- })
- .transpose()?;
- if let Some(ref file) = *license_file {
- if !pkg.root().join(file).exists() {
- bail!("the license file `{}` does not exist", file)
- }
- }
-
- // Do not upload if performing a dry run
- if dry_run {
- config.shell().warn("aborting upload due to dry run")?;
- return Ok(());
- }
-
- let string_features = match manifest.original().features() {
- Some(features) => features
- .iter()
- .map(|(feat, values)| {
- (
- feat.to_string(),
- values.iter().map(|fv| fv.to_string()).collect(),
- )
- })
- .collect::<BTreeMap<String, Vec<String>>>(),
- None => BTreeMap::new(),
- };
-
- let warnings = registry
- .publish(
- &NewCrate {
- name: pkg.name().to_string(),
- vers: pkg.version().to_string(),
- deps,
- features: string_features,
- authors: authors.clone(),
- description: description.clone(),
- homepage: homepage.clone(),
- documentation: documentation.clone(),
- keywords: keywords.clone(),
- categories: categories.clone(),
- readme: readme_content,
- readme_file: readme.clone(),
- repository: repository.clone(),
- license: license.clone(),
- license_file: license_file.clone(),
- badges: badges.clone(),
- links: links.clone(),
- rust_version: rust_version.clone(),
- },
- tarball,
- )
- .with_context(|| format!("failed to publish to registry at {}", registry.host()))?;
-
- if !warnings.invalid_categories.is_empty() {
- let msg = format!(
- "the following are not valid category slugs and were \
- ignored: {}. Please see https://crates.io/category_slugs \
- for the list of all category slugs. \
- ",
- warnings.invalid_categories.join(", ")
- );
- config.shell().warn(&msg)?;
- }
-
- if !warnings.invalid_badges.is_empty() {
- let msg = format!(
- "the following are not valid badges and were ignored: {}. \
- Either the badge type specified is unknown or a required \
- attribute is missing. Please see \
- https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata \
- for valid badge types and their required attributes.",
- warnings.invalid_badges.join(", ")
- );
- config.shell().warn(&msg)?;
- }
-
- if !warnings.other.is_empty() {
- for msg in warnings.other {
- config.shell().warn(&msg)?;
- }
- }
-
- Ok(())
-}
-
-fn wait_for_publish(
- config: &Config,
- registry_src: SourceId,
- pkg: &Package,
- timeout: std::time::Duration,
-) -> CargoResult<()> {
- let version_req = format!("={}", pkg.version());
- let mut source = SourceConfigMap::empty(config)?.load(registry_src, &HashSet::new())?;
- // Disable the source's built-in progress bars. Repeatedly showing a bunch
- // of independent progress bars can be a little confusing. There is an
- // overall progress bar managed here.
- source.set_quiet(true);
- let source_description = source.source_id().to_string();
- let query = Dependency::parse(pkg.name(), Some(&version_req), registry_src)?;
-
- let now = std::time::Instant::now();
- let sleep_time = std::time::Duration::from_secs(1);
- let max = timeout.as_secs() as usize;
- // Short does not include the registry name.
- let short_pkg_description = format!("{} v{}", pkg.name(), pkg.version());
- config.shell().status(
- "Uploaded",
- format!("{short_pkg_description} to {source_description}"),
- )?;
- config.shell().note(format!(
- "Waiting for `{short_pkg_description}` to be available at {source_description}.\n\
- You may press ctrl-c to skip waiting; the crate should be available shortly."
- ))?;
- let mut progress = Progress::with_style("Waiting", ProgressStyle::Ratio, config);
- progress.tick_now(0, max, "")?;
- let is_available = loop {
- {
- let _lock = config.acquire_package_cache_lock()?;
- // Force re-fetching the source
- //
- // As pulling from a git source is expensive, we track when we've done it within the
- // process to only do it once, but we are one of the rare cases that needs to do it
- // multiple times
- config
- .updated_sources()
- .remove(&source.replaced_source_id());
- source.invalidate_cache();
- let summaries = loop {
- // Exact to avoid returning all for path/git
- match source.query_vec(&query, QueryKind::Exact) {
- std::task::Poll::Ready(res) => {
- break res?;
- }
- std::task::Poll::Pending => source.block_until_ready()?,
- }
- };
- if !summaries.is_empty() {
- break true;
- }
- }
-
- let elapsed = now.elapsed();
- if timeout < elapsed {
- config.shell().warn(format!(
- "timed out waiting for `{short_pkg_description}` to be available in {source_description}",
- ))?;
- config.shell().note(
- "The registry may have a backlog that is delaying making the \
- crate available. The crate should be available soon.",
- )?;
- break false;
- }
-
- progress.tick_now(elapsed.as_secs() as usize, max, "")?;
- std::thread::sleep(sleep_time);
- };
- if is_available {
- config.shell().status(
- "Published",
- format!("{short_pkg_description} at {source_description}"),
- )?;
- }
-
- Ok(())
-}
-
-/// Returns the `Registry` and `Source` based on command-line and config settings.
-///
-/// * `token_from_cmdline`: The token from the command-line. If not set, uses the token
-/// from the config.
-/// * `index`: The index URL from the command-line.
-/// * `registry`: The registry name from the command-line. If neither
-/// `registry`, or `index` are set, then uses `crates-io`.
-/// * `force_update`: If `true`, forces the index to be updated.
-/// * `token_required`: If `true`, the token will be set.
-fn registry(
- config: &Config,
- token_from_cmdline: Option<Secret<&str>>,
- index: Option<&str>,
- registry: Option<&str>,
- force_update: bool,
- token_required: Option<auth::Mutation<'_>>,
-) -> CargoResult<(Registry, RegistrySourceIds)> {
- let source_ids = get_source_id(config, index, registry)?;
-
- if token_required.is_some() && index.is_some() && token_from_cmdline.is_none() {
- bail!("command-line argument --index requires --token to be specified");
- }
- if let Some(token) = token_from_cmdline {
- auth::cache_token(config, &source_ids.original, token);
- }
-
- let cfg = {
- let _lock = config.acquire_package_cache_lock()?;
- let mut src = RegistrySource::remote(source_ids.replacement, &HashSet::new(), config)?;
- // Only update the index if `force_update` is set.
- if force_update {
- src.invalidate_cache()
- }
- let cfg = loop {
- match src.config()? {
- Poll::Pending => src
- .block_until_ready()
- .with_context(|| format!("failed to update {}", source_ids.replacement))?,
- Poll::Ready(cfg) => break cfg,
- }
- };
- cfg.expect("remote registries must have config")
- };
- let api_host = cfg
- .api
- .ok_or_else(|| format_err!("{} does not support API commands", source_ids.replacement))?;
- let token = if token_required.is_some() || cfg.auth_required {
- Some(auth::auth_token(
- config,
- &source_ids.original,
- None,
- token_required,
- )?)
- } else {
- None
- };
- let handle = http_handle(config)?;
- Ok((
- Registry::new_handle(api_host, token, handle, cfg.auth_required),
- source_ids,
- ))
-}
-
-/// Creates a new HTTP handle with appropriate global configuration for cargo.
-pub fn http_handle(config: &Config) -> CargoResult<Easy> {
- let (mut handle, timeout) = http_handle_and_timeout(config)?;
- timeout.configure(&mut handle)?;
- Ok(handle)
-}
-
-pub fn http_handle_and_timeout(config: &Config) -> CargoResult<(Easy, HttpTimeout)> {
- if config.frozen() {
- bail!(
- "attempting to make an HTTP request, but --frozen was \
- specified"
- )
- }
- if config.offline() {
- bail!(
- "attempting to make an HTTP request, but --offline was \
- specified"
- )
- }
-
- // The timeout option for libcurl by default times out the entire transfer,
- // but we probably don't want this. Instead we only set timeouts for the
- // connect phase as well as a "low speed" timeout so if we don't receive
- // many bytes in a large-ish period of time then we time out.
- let mut handle = Easy::new();
- let timeout = configure_http_handle(config, &mut handle)?;
- 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(
- 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) = network::proxy::http_proxy(http) {
- handle.proxy(&proxy)?;
- }
- if let Some(cainfo) = &http.cainfo {
- let cainfo = cainfo.resolve_path(config);
- handle.cainfo(&cainfo)?;
- }
- if let Some(check) = http.check_revoke {
- handle.ssl_options(SslOpt::new().no_revoke(!check))?;
- }
-
- if let Some(user_agent) = &http.user_agent {
- handle.useragent(user_agent)?;
- } else {
- handle.useragent(&format!("cargo {}", version()))?;
- }
-
- fn to_ssl_version(s: &str) -> CargoResult<SslVersion> {
- let version = match s {
- "default" => SslVersion::Default,
- "tlsv1" => SslVersion::Tlsv1,
- "tlsv1.0" => SslVersion::Tlsv10,
- "tlsv1.1" => SslVersion::Tlsv11,
- "tlsv1.2" => SslVersion::Tlsv12,
- "tlsv1.3" => SslVersion::Tlsv13,
- _ => bail!(
- "Invalid ssl version `{s}`,\
- choose from 'default', 'tlsv1', 'tlsv1.0', 'tlsv1.1', 'tlsv1.2', 'tlsv1.3'."
- ),
- };
- Ok(version)
- }
-
- // Empty string accept encoding expands to the encodings supported by the current libcurl.
- handle.accept_encoding("")?;
- if let Some(ssl_version) = &http.ssl_version {
- match ssl_version {
- SslVersionConfig::Single(s) => {
- let version = to_ssl_version(s.as_str())?;
- handle.ssl_version(version)?;
- }
- SslVersionConfig::Range(SslVersionConfigRange { min, max }) => {
- let min_version = min
- .as_ref()
- .map_or(Ok(SslVersion::Default), |s| to_ssl_version(s))?;
- let max_version = max
- .as_ref()
- .map_or(Ok(SslVersion::Default), |s| to_ssl_version(s))?;
- handle.ssl_min_max_version(min_version, max_version)?;
- }
- }
- } else if cfg!(windows) {
- // This is a temporary workaround for some bugs with libcurl and
- // schannel and TLS 1.3.
- //
- // Our libcurl on Windows is usually built with schannel.
- // On Windows 11 (or Windows Server 2022), libcurl recently (late
- // 2022) gained support for TLS 1.3 with schannel, and it now defaults
- // to 1.3. Unfortunately there have been some bugs with this.
- // https://github.com/curl/curl/issues/9431 is the most recent. Once
- // that has been fixed, and some time has passed where we can be more
- // confident that the 1.3 support won't cause issues, this can be
- // removed.
- //
- // Windows 10 is unaffected. libcurl does not support TLS 1.3 on
- // Windows 10. (Windows 10 sorta had support, but it required enabling
- // an advanced option in the registry which was buggy, and libcurl
- // does runtime checks to prevent it.)
- handle.ssl_min_max_version(SslVersion::Default, SslVersion::Tlsv12)?;
- }
-
- if let Some(true) = http.debug {
- handle.verbose(true)?;
- log::debug!("{:#?}", curl::Version::get());
- handle.debug_function(|kind, data| {
- let (prefix, level) = match kind {
- InfoType::Text => ("*", Level::Debug),
- InfoType::HeaderIn => ("<", Level::Debug),
- InfoType::HeaderOut => (">", Level::Debug),
- InfoType::DataIn => ("{", Level::Trace),
- InfoType::DataOut => ("}", Level::Trace),
- 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 starts_with_ignore_case(line, "authorization:") {
- line = "Authorization: [REDACTED]";
- } 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);
- }
- }
- Err(_) => {
- log!(
- level,
- "http-debug: {} ({} bytes of data)",
- prefix,
- data.len()
- );
- }
- }
- })?;
- }
-
- HttpTimeout::new(config)
-}
-
-#[must_use]
-pub struct HttpTimeout {
- pub dur: Duration,
- pub low_speed_limit: u32,
-}
-
-impl HttpTimeout {
- pub fn new(config: &Config) -> CargoResult<HttpTimeout> {
- let http_config = config.http_config()?;
- let low_speed_limit = http_config.low_speed_limit.unwrap_or(10);
- let seconds = http_config
- .timeout
- .or_else(|| {
- config
- .get_env("HTTP_TIMEOUT")
- .ok()
- .and_then(|s| s.parse().ok())
- })
- .unwrap_or(30);
- Ok(HttpTimeout {
- dur: Duration::new(seconds, 0),
- low_speed_limit,
- })
- }
-
- pub fn configure(&self, handle: &mut Easy) -> CargoResult<()> {
- // The timeout option for libcurl by default times out the entire
- // transfer, but we probably don't want this. Instead we only set
- // timeouts for the connect phase as well as a "low speed" timeout so
- // if we don't receive many bytes in a large-ish period of time then we
- // time out.
- handle.connect_timeout(self.dur)?;
- handle.low_speed_time(self.dur)?;
- handle.low_speed_limit(self.low_speed_limit)?;
- Ok(())
- }
-}
-
-pub fn registry_login(
- config: &Config,
- token: Option<Secret<&str>>,
- reg: Option<&str>,
- generate_keypair: bool,
- secret_key_required: bool,
- key_subject: Option<&str>,
-) -> CargoResult<()> {
- let source_ids = get_source_id(config, None, reg)?;
- let reg_cfg = auth::registry_credential_config(config, &source_ids.original)?;
-
- let login_url = match registry(config, token.clone(), None, reg, false, None) {
- Ok((registry, _)) => Some(format!("{}/me", registry.host())),
- Err(e) if e.is::<AuthorizationError>() => e
- .downcast::<AuthorizationError>()
- .unwrap()
- .login_url
- .map(|u| u.to_string()),
- Err(e) => return Err(e),
- };
- let new_token;
- if generate_keypair || secret_key_required || key_subject.is_some() {
- if !config.cli_unstable().registry_auth {
- let flag = if generate_keypair {
- "generate-keypair"
- } else if secret_key_required {
- "secret-key"
- } else if key_subject.is_some() {
- "key-subject"
- } else {
- unreachable!("how did we get here");
- };
- bail!(
- "the `{flag}` flag is unstable, pass `-Z registry-auth` to enable it\n\
- See https://github.com/rust-lang/cargo/issues/10519 for more \
- information about the `{flag}` flag."
- );
- }
- assert!(token.is_none());
- // we are dealing with asymmetric tokens
- let (old_secret_key, old_key_subject) = match &reg_cfg {
- RegistryCredentialConfig::AsymmetricKey((old_secret_key, old_key_subject)) => {
- (Some(old_secret_key), old_key_subject.clone())
- }
- _ => (None, None),
- };
- let secret_key: Secret<String>;
- if generate_keypair {
- assert!(!secret_key_required);
- let kp = AsymmetricKeyPair::<pasetors::version3::V3>::generate().unwrap();
- secret_key = Secret::default().map(|mut key| {
- FormatAsPaserk::fmt(&kp.secret, &mut key).unwrap();
- key
- });
- } else if secret_key_required {
- assert!(!generate_keypair);
- drop_println!(config, "please paste the API secret key below");
- secret_key = Secret::default()
- .map(|mut line| {
- let input = io::stdin();
- input
- .lock()
- .read_line(&mut line)
- .with_context(|| "failed to read stdin")
- .map(|_| line.trim().to_string())
- })
- .transpose()?;
- } else {
- secret_key = old_secret_key
- .cloned()
- .ok_or_else(|| anyhow!("need a secret_key to set a key_subject"))?;
- }
- if let Some(p) = paserk_public_from_paserk_secret(secret_key.as_deref()) {
- drop_println!(config, "{}", &p);
- } else {
- bail!("not a validly formatted PASERK secret key");
- }
- new_token = RegistryCredentialConfig::AsymmetricKey((
- secret_key,
- match key_subject {
- Some(key_subject) => Some(key_subject.to_string()),
- None => old_key_subject,
- },
- ));
- } else {
- new_token = RegistryCredentialConfig::Token(match token {
- Some(token) => token.owned(),
- None => {
- if let Some(login_url) = login_url {
- drop_println!(
- config,
- "please paste the token found on {} below",
- login_url
- )
- } else {
- drop_println!(
- config,
- "please paste the token for {} below",
- source_ids.original.display_registry_name()
- )
- }
-
- let mut line = String::new();
- let input = io::stdin();
- input
- .lock()
- .read_line(&mut line)
- .with_context(|| "failed to read stdin")?;
- // Automatically remove `cargo login` from an inputted token to
- // allow direct pastes from `registry.host()`/me.
- Secret::from(line.replace("cargo login", "").trim().to_string())
- }
- });
-
- if let Some(tok) = new_token.as_token() {
- crates_io::check_token(tok.as_ref().expose())?;
- }
- }
- if &reg_cfg == &new_token {
- config.shell().status("Login", "already logged in")?;
- return Ok(());
- }
-
- auth::login(config, &source_ids.original, new_token)?;
-
- config.shell().status(
- "Login",
- format!("token for `{}` saved", reg.unwrap_or(CRATES_IO_DOMAIN)),
- )?;
- Ok(())
-}
-
-pub fn registry_logout(config: &Config, reg: Option<&str>) -> CargoResult<()> {
- let source_ids = get_source_id(config, None, reg)?;
- let reg_cfg = auth::registry_credential_config(config, &source_ids.original)?;
- let reg_name = source_ids.original.display_registry_name();
- if reg_cfg.is_none() {
- config.shell().status(
- "Logout",
- format!("not currently logged in to `{}`", reg_name),
- )?;
- return Ok(());
- }
- auth::logout(config, &source_ids.original)?;
- config.shell().status(
- "Logout",
- format!(
- "token for `{}` has been removed from local storage",
- reg_name
- ),
- )?;
- let location = if source_ids.original.is_crates_io() {
- "<https://crates.io/me>".to_string()
- } else {
- // The URL for the source requires network access to load the config.
- // That could be a fairly heavy operation to perform just to provide a
- // help message, so for now this just provides some generic text.
- // Perhaps in the future this could have an API to fetch the config if
- // it is cached, but avoid network access otherwise?
- format!("the `{reg_name}` website")
- };
- config.shell().note(format!(
- "This does not revoke the token on the registry server.\n \
- If you need to revoke the token, visit {location} and follow the instructions there."
- ))?;
- Ok(())
-}
-
-pub struct OwnersOptions {
- pub krate: Option<String>,
- pub token: Option<Secret<String>>,
- pub index: Option<String>,
- pub to_add: Option<Vec<String>>,
- pub to_remove: Option<Vec<String>>,
- pub list: bool,
- pub registry: Option<String>,
-}
-
-pub fn modify_owners(config: &Config, opts: &OwnersOptions) -> CargoResult<()> {
- let name = match opts.krate {
- Some(ref name) => name.clone(),
- None => {
- let manifest_path = find_root_manifest_for_wd(config.cwd())?;
- let ws = Workspace::new(&manifest_path, config)?;
- ws.current()?.package_id().name().to_string()
- }
- };
-
- let mutation = auth::Mutation::Owners { name: &name };
-
- let (mut registry, _) = registry(
- config,
- opts.token.as_ref().map(Secret::as_deref),
- opts.index.as_deref(),
- opts.registry.as_deref(),
- true,
- Some(mutation),
- )?;
-
- if let Some(ref v) = opts.to_add {
- let v = v.iter().map(|s| &s[..]).collect::<Vec<_>>();
- let msg = registry.add_owners(&name, &v).with_context(|| {
- format!(
- "failed to invite owners to crate `{}` on registry at {}",
- name,
- registry.host()
- )
- })?;
-
- config.shell().status("Owner", msg)?;
- }
-
- if let Some(ref v) = opts.to_remove {
- let v = v.iter().map(|s| &s[..]).collect::<Vec<_>>();
- config
- .shell()
- .status("Owner", format!("removing {:?} from crate {}", v, name))?;
- registry.remove_owners(&name, &v).with_context(|| {
- format!(
- "failed to remove owners from crate `{}` on registry at {}",
- name,
- registry.host()
- )
- })?;
- }
-
- if opts.list {
- let owners = registry.list_owners(&name).with_context(|| {
- format!(
- "failed to list owners of crate `{}` on registry at {}",
- name,
- registry.host()
- )
- })?;
- for owner in owners.iter() {
- drop_print!(config, "{}", owner.login);
- match (owner.name.as_ref(), owner.email.as_ref()) {
- (Some(name), Some(email)) => drop_println!(config, " ({} <{}>)", name, email),
- (Some(s), None) | (None, Some(s)) => drop_println!(config, " ({})", s),
- (None, None) => drop_println!(config),
- }
- }
- }
-
- Ok(())
-}
-
-pub fn yank(
- config: &Config,
- krate: Option<String>,
- version: Option<String>,
- token: Option<Secret<String>>,
- index: Option<String>,
- undo: bool,
- reg: Option<String>,
-) -> CargoResult<()> {
- let name = match krate {
- Some(name) => name,
- None => {
- let manifest_path = find_root_manifest_for_wd(config.cwd())?;
- let ws = Workspace::new(&manifest_path, config)?;
- ws.current()?.package_id().name().to_string()
- }
- };
- let version = match version {
- Some(v) => v,
- None => bail!("a version must be specified to yank"),
- };
-
- let message = if undo {
- auth::Mutation::Unyank {
- name: &name,
- vers: &version,
- }
- } else {
- auth::Mutation::Yank {
- name: &name,
- vers: &version,
- }
- };
-
- let (mut registry, _) = registry(
- config,
- token.as_ref().map(Secret::as_deref),
- index.as_deref(),
- reg.as_deref(),
- true,
- Some(message),
- )?;
-
- let package_spec = format!("{}@{}", name, version);
- if undo {
- config.shell().status("Unyank", package_spec)?;
- registry.unyank(&name, &version).with_context(|| {
- format!(
- "failed to undo a yank from the registry at {}",
- registry.host()
- )
- })?;
- } else {
- config.shell().status("Yank", package_spec)?;
- registry
- .yank(&name, &version)
- .with_context(|| format!("failed to yank from the registry at {}", registry.host()))?;
- }
-
- Ok(())
-}
-
-/// Gets the SourceId for an index or registry setting.
-///
-/// The `index` and `reg` values are from the command-line or config settings.
-/// If both are None, and no source-replacement is configured, returns the source for crates.io.
-/// If both are None, and source replacement is configured, returns an error.
-///
-/// The source for crates.io may be GitHub, index.crates.io, or a test-only registry depending
-/// on configuration.
-///
-/// If `reg` is set, source replacement is not followed.
-///
-/// The return value is a pair of `SourceId`s: The first may be a built-in replacement of
-/// crates.io (such as index.crates.io), while the second is always the original source.
-fn get_source_id(
- config: &Config,
- index: Option<&str>,
- reg: Option<&str>,
-) -> CargoResult<RegistrySourceIds> {
- let sid = match (reg, index) {
- (None, None) => SourceId::crates_io(config)?,
- (_, Some(i)) => SourceId::for_registry(&i.into_url()?)?,
- (Some(r), None) => SourceId::alt_registry(config, r)?,
- };
- // Load source replacements that are built-in to Cargo.
- let builtin_replacement_sid = SourceConfigMap::empty(config)?
- .load(sid, &HashSet::new())?
- .replaced_source_id();
- let replacement_sid = SourceConfigMap::new(config)?
- .load(sid, &HashSet::new())?
- .replaced_source_id();
- if reg.is_none() && index.is_none() && replacement_sid != builtin_replacement_sid {
- // Neither --registry nor --index was passed and the user has configured source-replacement.
- if let Some(replacement_name) = replacement_sid.alt_registry_key() {
- bail!("crates-io is replaced with remote registry {replacement_name};\ninclude `--registry {replacement_name}` or `--registry crates-io`");
- } else {
- bail!("crates-io is replaced with non-remote-registry source {replacement_sid};\ninclude `--registry crates-io` to use crates.io");
- }
- } else {
- Ok(RegistrySourceIds {
- original: sid,
- replacement: builtin_replacement_sid,
- })
- }
-}
-
-struct RegistrySourceIds {
- /// Use when looking up the auth token, or writing out `Cargo.lock`
- original: SourceId,
- /// Use when interacting with the source (querying / publishing , etc)
- ///
- /// The source for crates.io may be replaced by a built-in source for accessing crates.io with
- /// the sparse protocol, or a source for the testing framework (when the replace_crates_io
- /// function is used)
- ///
- /// User-defined source replacement is not applied.
- replacement: SourceId,
-}
-
-pub fn search(
- query: &str,
- config: &Config,
- index: Option<String>,
- limit: u32,
- reg: Option<String>,
-) -> CargoResult<()> {
- let (mut registry, source_ids) =
- registry(config, None, index.as_deref(), reg.as_deref(), false, None)?;
- let (crates, total_crates) = registry.search(query, limit).with_context(|| {
- format!(
- "failed to retrieve search results from the registry at {}",
- registry.host()
- )
- })?;
-
- let names = crates
- .iter()
- .map(|krate| format!("{} = \"{}\"", krate.name, krate.max_version))
- .collect::<Vec<String>>();
-
- let description_margin = names.iter().map(|s| s.len() + 4).max().unwrap_or_default();
-
- let description_length = cmp::max(80, 128 - description_margin);
-
- let descriptions = crates.iter().map(|krate| {
- krate
- .description
- .as_ref()
- .map(|desc| truncate_with_ellipsis(&desc.replace("\n", " "), description_length))
- });
-
- for (name, description) in names.into_iter().zip(descriptions) {
- let line = match description {
- Some(desc) => {
- let space = repeat(' ')
- .take(description_margin - name.len())
- .collect::<String>();
- name + &space + "# " + &desc
- }
- None => name,
- };
- let mut fragments = line.split(query).peekable();
- while let Some(fragment) = fragments.next() {
- let _ = config.shell().write_stdout(fragment, &ColorSpec::new());
- if fragments.peek().is_some() {
- let _ = config
- .shell()
- .write_stdout(query, &ColorSpec::new().set_bold(true).set_fg(Some(Green)));
- }
- }
- let _ = config.shell().write_stdout("\n", &ColorSpec::new());
- }
-
- let search_max_limit = 100;
- if total_crates > limit && limit < search_max_limit {
- let _ = config.shell().write_stdout(
- format_args!(
- "... and {} crates more (use --limit N to see more)\n",
- total_crates - limit
- ),
- &ColorSpec::new(),
- );
- } else if total_crates > limit && limit >= search_max_limit {
- let extra = if source_ids.original.is_crates_io() {
- let url = Url::parse_with_params("https://crates.io/search", &[("q", query)])?;
- format!(" (go to {url} to see more)")
- } else {
- String::new()
- };
- let _ = config.shell().write_stdout(
- format_args!("... and {} crates more{}\n", total_crates - limit, extra),
- &ColorSpec::new(),
- );
- }
-
- Ok(())
-}
diff --git a/src/tools/cargo/src/cargo/ops/registry/login.rs b/src/tools/cargo/src/cargo/ops/registry/login.rs
new file mode 100644
index 000000000..1e2b3a87b
--- /dev/null
+++ b/src/tools/cargo/src/cargo/ops/registry/login.rs
@@ -0,0 +1,160 @@
+//! Interacts with the registry [login API][1].
+//!
+//! This doesn't really call any web API at this moment. Instead, it's just an
+//! operation for `cargo login`.
+//!
+//! [1]: https://doc.rust-lang.org/nightly/cargo/reference/registry-web-api.html#login
+
+use std::io;
+use std::io::BufRead;
+
+use anyhow::anyhow;
+use anyhow::bail;
+use anyhow::Context as _;
+use pasetors::keys::AsymmetricKeyPair;
+use pasetors::keys::Generate as _;
+use pasetors::paserk::FormatAsPaserk;
+
+use crate::drop_println;
+use crate::ops::RegistryCredentialConfig;
+use crate::sources::CRATES_IO_DOMAIN;
+use crate::util::auth;
+use crate::util::auth::paserk_public_from_paserk_secret;
+use crate::util::auth::AuthorizationError;
+use crate::util::auth::Secret;
+use crate::CargoResult;
+use crate::Config;
+
+use super::get_source_id;
+
+pub fn registry_login(
+ config: &Config,
+ token: Option<Secret<&str>>,
+ reg: Option<&str>,
+ generate_keypair: bool,
+ secret_key_required: bool,
+ key_subject: Option<&str>,
+) -> CargoResult<()> {
+ let source_ids = get_source_id(config, None, reg)?;
+ let reg_cfg = auth::registry_credential_config(config, &source_ids.original)?;
+
+ let login_url = match super::registry(config, token.clone(), None, reg, false, None) {
+ Ok((registry, _)) => Some(format!("{}/me", registry.host())),
+ Err(e) if e.is::<AuthorizationError>() => e
+ .downcast::<AuthorizationError>()
+ .unwrap()
+ .login_url
+ .map(|u| u.to_string()),
+ Err(e) => return Err(e),
+ };
+ let new_token;
+ if generate_keypair || secret_key_required || key_subject.is_some() {
+ if !config.cli_unstable().registry_auth {
+ let flag = if generate_keypair {
+ "generate-keypair"
+ } else if secret_key_required {
+ "secret-key"
+ } else if key_subject.is_some() {
+ "key-subject"
+ } else {
+ unreachable!("how did we get here");
+ };
+ bail!(
+ "the `{flag}` flag is unstable, pass `-Z registry-auth` to enable it\n\
+ See https://github.com/rust-lang/cargo/issues/10519 for more \
+ information about the `{flag}` flag."
+ );
+ }
+ assert!(token.is_none());
+ // we are dealing with asymmetric tokens
+ let (old_secret_key, old_key_subject) = match &reg_cfg {
+ RegistryCredentialConfig::AsymmetricKey((old_secret_key, old_key_subject)) => {
+ (Some(old_secret_key), old_key_subject.clone())
+ }
+ _ => (None, None),
+ };
+ let secret_key: Secret<String>;
+ if generate_keypair {
+ assert!(!secret_key_required);
+ let kp = AsymmetricKeyPair::<pasetors::version3::V3>::generate().unwrap();
+ secret_key = Secret::default().map(|mut key| {
+ FormatAsPaserk::fmt(&kp.secret, &mut key).unwrap();
+ key
+ });
+ } else if secret_key_required {
+ assert!(!generate_keypair);
+ drop_println!(config, "please paste the API secret key below");
+ secret_key = Secret::default()
+ .map(|mut line| {
+ let input = io::stdin();
+ input
+ .lock()
+ .read_line(&mut line)
+ .with_context(|| "failed to read stdin")
+ .map(|_| line.trim().to_string())
+ })
+ .transpose()?;
+ } else {
+ secret_key = old_secret_key
+ .cloned()
+ .ok_or_else(|| anyhow!("need a secret_key to set a key_subject"))?;
+ }
+ if let Some(p) = paserk_public_from_paserk_secret(secret_key.as_deref()) {
+ drop_println!(config, "{}", &p);
+ } else {
+ bail!("not a validly formatted PASERK secret key");
+ }
+ new_token = RegistryCredentialConfig::AsymmetricKey((
+ secret_key,
+ match key_subject {
+ Some(key_subject) => Some(key_subject.to_string()),
+ None => old_key_subject,
+ },
+ ));
+ } else {
+ new_token = RegistryCredentialConfig::Token(match token {
+ Some(token) => token.owned(),
+ None => {
+ if let Some(login_url) = login_url {
+ drop_println!(
+ config,
+ "please paste the token found on {} below",
+ login_url
+ )
+ } else {
+ drop_println!(
+ config,
+ "please paste the token for {} below",
+ source_ids.original.display_registry_name()
+ )
+ }
+
+ let mut line = String::new();
+ let input = io::stdin();
+ input
+ .lock()
+ .read_line(&mut line)
+ .with_context(|| "failed to read stdin")?;
+ // Automatically remove `cargo login` from an inputted token to
+ // allow direct pastes from `registry.host()`/me.
+ Secret::from(line.replace("cargo login", "").trim().to_string())
+ }
+ });
+
+ if let Some(tok) = new_token.as_token() {
+ crates_io::check_token(tok.as_ref().expose())?;
+ }
+ }
+ if &reg_cfg == &new_token {
+ config.shell().status("Login", "already logged in")?;
+ return Ok(());
+ }
+
+ auth::login(config, &source_ids.original, new_token)?;
+
+ config.shell().status(
+ "Login",
+ format!("token for `{}` saved", reg.unwrap_or(CRATES_IO_DOMAIN)),
+ )?;
+ Ok(())
+}
diff --git a/src/tools/cargo/src/cargo/ops/registry/logout.rs b/src/tools/cargo/src/cargo/ops/registry/logout.rs
new file mode 100644
index 000000000..59f2d9261
--- /dev/null
+++ b/src/tools/cargo/src/cargo/ops/registry/logout.rs
@@ -0,0 +1,42 @@
+//! Interacts with the registry logout.
+//!
+//! There is no web API for logout at this moment. Instead, it's just an
+//! operation for `cargo logout`.
+
+use crate::util::auth;
+use crate::CargoResult;
+use crate::Config;
+
+use super::get_source_id;
+
+pub fn registry_logout(config: &Config, reg: Option<&str>) -> CargoResult<()> {
+ let source_ids = get_source_id(config, None, reg)?;
+ let reg_cfg = auth::registry_credential_config(config, &source_ids.original)?;
+ let reg_name = source_ids.original.display_registry_name();
+ if reg_cfg.is_none() {
+ config
+ .shell()
+ .status("Logout", format!("not currently logged in to `{reg_name}`"))?;
+ return Ok(());
+ }
+ auth::logout(config, &source_ids.original)?;
+ config.shell().status(
+ "Logout",
+ format!("token for `{reg_name}` has been removed from local storage"),
+ )?;
+ let location = if source_ids.original.is_crates_io() {
+ "<https://crates.io/me>".to_string()
+ } else {
+ // The URL for the source requires network access to load the config.
+ // That could be a fairly heavy operation to perform just to provide a
+ // help message, so for now this just provides some generic text.
+ // Perhaps in the future this could have an API to fetch the config if
+ // it is cached, but avoid network access otherwise?
+ format!("the `{reg_name}` website")
+ };
+ config.shell().note(format!(
+ "This does not revoke the token on the registry server.\n \
+ If you need to revoke the token, visit {location} and follow the instructions there."
+ ))?;
+ Ok(())
+}
diff --git a/src/tools/cargo/src/cargo/ops/registry/mod.rs b/src/tools/cargo/src/cargo/ops/registry/mod.rs
new file mode 100644
index 000000000..ecb610ddd
--- /dev/null
+++ b/src/tools/cargo/src/cargo/ops/registry/mod.rs
@@ -0,0 +1,213 @@
+//! Operations that interact with the [registry web API][1].
+//!
+//! [1]: https://doc.rust-lang.org/nightly/cargo/reference/registry-web-api.html
+
+mod login;
+mod logout;
+mod owner;
+mod publish;
+mod search;
+mod yank;
+
+use std::collections::HashSet;
+use std::path::PathBuf;
+use std::str;
+use std::task::Poll;
+
+use anyhow::{bail, format_err, Context as _};
+use crates_io::{self, Registry};
+
+use crate::core::source::Source;
+use crate::core::SourceId;
+use crate::sources::{RegistrySource, SourceConfigMap};
+use crate::util::auth::{self, Secret};
+use crate::util::config::Config;
+use crate::util::errors::CargoResult;
+use crate::util::network::http::http_handle;
+use crate::util::IntoUrl;
+
+pub use self::login::registry_login;
+pub use self::logout::registry_logout;
+pub use self::owner::modify_owners;
+pub use self::owner::OwnersOptions;
+pub use self::publish::publish;
+pub use self::publish::PublishOpts;
+pub use self::search::search;
+pub use self::yank::yank;
+
+/// Registry settings loaded from config files.
+///
+/// This is loaded based on the `--registry` flag and the config settings.
+#[derive(Debug, PartialEq)]
+pub enum RegistryCredentialConfig {
+ None,
+ /// The authentication token.
+ Token(Secret<String>),
+ /// Process used for fetching a token.
+ Process((PathBuf, Vec<String>)),
+ /// Secret Key and subject for Asymmetric tokens.
+ AsymmetricKey((Secret<String>, Option<String>)),
+}
+
+impl RegistryCredentialConfig {
+ /// Returns `true` if the credential is [`None`].
+ ///
+ /// [`None`]: Self::None
+ pub fn is_none(&self) -> bool {
+ matches!(self, Self::None)
+ }
+ /// Returns `true` if the credential is [`Token`].
+ ///
+ /// [`Token`]: Self::Token
+ pub fn is_token(&self) -> bool {
+ matches!(self, Self::Token(..))
+ }
+ /// Returns `true` if the credential is [`AsymmetricKey`].
+ ///
+ /// [`AsymmetricKey`]: RegistryCredentialConfig::AsymmetricKey
+ pub fn is_asymmetric_key(&self) -> bool {
+ matches!(self, Self::AsymmetricKey(..))
+ }
+ pub fn as_token(&self) -> Option<Secret<&str>> {
+ if let Self::Token(v) = self {
+ Some(v.as_deref())
+ } else {
+ None
+ }
+ }
+ pub fn as_process(&self) -> Option<&(PathBuf, Vec<String>)> {
+ if let Self::Process(v) = self {
+ Some(v)
+ } else {
+ None
+ }
+ }
+ pub fn as_asymmetric_key(&self) -> Option<&(Secret<String>, Option<String>)> {
+ if let Self::AsymmetricKey(v) = self {
+ Some(v)
+ } else {
+ None
+ }
+ }
+}
+
+/// Returns the `Registry` and `Source` based on command-line and config settings.
+///
+/// * `token_from_cmdline`: The token from the command-line. If not set, uses the token
+/// from the config.
+/// * `index`: The index URL from the command-line.
+/// * `registry`: The registry name from the command-line. If neither
+/// `registry`, or `index` are set, then uses `crates-io`.
+/// * `force_update`: If `true`, forces the index to be updated.
+/// * `token_required`: If `true`, the token will be set.
+fn registry(
+ config: &Config,
+ token_from_cmdline: Option<Secret<&str>>,
+ index: Option<&str>,
+ registry: Option<&str>,
+ force_update: bool,
+ token_required: Option<auth::Mutation<'_>>,
+) -> CargoResult<(Registry, RegistrySourceIds)> {
+ let source_ids = get_source_id(config, index, registry)?;
+
+ if token_required.is_some() && index.is_some() && token_from_cmdline.is_none() {
+ bail!("command-line argument --index requires --token to be specified");
+ }
+ if let Some(token) = token_from_cmdline {
+ auth::cache_token(config, &source_ids.original, token);
+ }
+
+ let cfg = {
+ let _lock = config.acquire_package_cache_lock()?;
+ let mut src = RegistrySource::remote(source_ids.replacement, &HashSet::new(), config)?;
+ // Only update the index if `force_update` is set.
+ if force_update {
+ src.invalidate_cache()
+ }
+ let cfg = loop {
+ match src.config()? {
+ Poll::Pending => src
+ .block_until_ready()
+ .with_context(|| format!("failed to update {}", source_ids.replacement))?,
+ Poll::Ready(cfg) => break cfg,
+ }
+ };
+ cfg.expect("remote registries must have config")
+ };
+ let api_host = cfg
+ .api
+ .ok_or_else(|| format_err!("{} does not support API commands", source_ids.replacement))?;
+ let token = if token_required.is_some() || cfg.auth_required {
+ Some(auth::auth_token(
+ config,
+ &source_ids.original,
+ None,
+ token_required,
+ )?)
+ } else {
+ None
+ };
+ let handle = http_handle(config)?;
+ Ok((
+ Registry::new_handle(api_host, token, handle, cfg.auth_required),
+ source_ids,
+ ))
+}
+
+/// Gets the SourceId for an index or registry setting.
+///
+/// The `index` and `reg` values are from the command-line or config settings.
+/// If both are None, and no source-replacement is configured, returns the source for crates.io.
+/// If both are None, and source replacement is configured, returns an error.
+///
+/// The source for crates.io may be GitHub, index.crates.io, or a test-only registry depending
+/// on configuration.
+///
+/// If `reg` is set, source replacement is not followed.
+///
+/// The return value is a pair of `SourceId`s: The first may be a built-in replacement of
+/// crates.io (such as index.crates.io), while the second is always the original source.
+fn get_source_id(
+ config: &Config,
+ index: Option<&str>,
+ reg: Option<&str>,
+) -> CargoResult<RegistrySourceIds> {
+ let sid = match (reg, index) {
+ (None, None) => SourceId::crates_io(config)?,
+ (_, Some(i)) => SourceId::for_registry(&i.into_url()?)?,
+ (Some(r), None) => SourceId::alt_registry(config, r)?,
+ };
+ // Load source replacements that are built-in to Cargo.
+ let builtin_replacement_sid = SourceConfigMap::empty(config)?
+ .load(sid, &HashSet::new())?
+ .replaced_source_id();
+ let replacement_sid = SourceConfigMap::new(config)?
+ .load(sid, &HashSet::new())?
+ .replaced_source_id();
+ if reg.is_none() && index.is_none() && replacement_sid != builtin_replacement_sid {
+ // Neither --registry nor --index was passed and the user has configured source-replacement.
+ if let Some(replacement_name) = replacement_sid.alt_registry_key() {
+ bail!("crates-io is replaced with remote registry {replacement_name};\ninclude `--registry {replacement_name}` or `--registry crates-io`");
+ } else {
+ bail!("crates-io is replaced with non-remote-registry source {replacement_sid};\ninclude `--registry crates-io` to use crates.io");
+ }
+ } else {
+ Ok(RegistrySourceIds {
+ original: sid,
+ replacement: builtin_replacement_sid,
+ })
+ }
+}
+
+struct RegistrySourceIds {
+ /// Use when looking up the auth token, or writing out `Cargo.lock`
+ original: SourceId,
+ /// Use when interacting with the source (querying / publishing , etc)
+ ///
+ /// The source for crates.io may be replaced by a built-in source for accessing crates.io with
+ /// the sparse protocol, or a source for the testing framework (when the replace_crates_io
+ /// function is used)
+ ///
+ /// User-defined source replacement is not applied.
+ replacement: SourceId,
+}
diff --git a/src/tools/cargo/src/cargo/ops/registry/owner.rs b/src/tools/cargo/src/cargo/ops/registry/owner.rs
new file mode 100644
index 000000000..e53e07cb8
--- /dev/null
+++ b/src/tools/cargo/src/cargo/ops/registry/owner.rs
@@ -0,0 +1,93 @@
+//! Interacts with the registry [owners API][1].
+//!
+//! [1]: https://doc.rust-lang.org/nightly/cargo/reference/registry-web-api.html#owners
+
+use anyhow::Context as _;
+
+use crate::core::Workspace;
+use crate::drop_print;
+use crate::drop_println;
+use crate::util::auth;
+use crate::util::auth::Secret;
+use crate::util::important_paths::find_root_manifest_for_wd;
+use crate::CargoResult;
+use crate::Config;
+
+pub struct OwnersOptions {
+ pub krate: Option<String>,
+ pub token: Option<Secret<String>>,
+ pub index: Option<String>,
+ pub to_add: Option<Vec<String>>,
+ pub to_remove: Option<Vec<String>>,
+ pub list: bool,
+ pub registry: Option<String>,
+}
+
+pub fn modify_owners(config: &Config, opts: &OwnersOptions) -> CargoResult<()> {
+ let name = match opts.krate {
+ Some(ref name) => name.clone(),
+ None => {
+ let manifest_path = find_root_manifest_for_wd(config.cwd())?;
+ let ws = Workspace::new(&manifest_path, config)?;
+ ws.current()?.package_id().name().to_string()
+ }
+ };
+
+ let mutation = auth::Mutation::Owners { name: &name };
+
+ let (mut registry, _) = super::registry(
+ config,
+ opts.token.as_ref().map(Secret::as_deref),
+ opts.index.as_deref(),
+ opts.registry.as_deref(),
+ true,
+ Some(mutation),
+ )?;
+
+ if let Some(ref v) = opts.to_add {
+ let v = v.iter().map(|s| &s[..]).collect::<Vec<_>>();
+ let msg = registry.add_owners(&name, &v).with_context(|| {
+ format!(
+ "failed to invite owners to crate `{}` on registry at {}",
+ name,
+ registry.host()
+ )
+ })?;
+
+ config.shell().status("Owner", msg)?;
+ }
+
+ if let Some(ref v) = opts.to_remove {
+ let v = v.iter().map(|s| &s[..]).collect::<Vec<_>>();
+ config
+ .shell()
+ .status("Owner", format!("removing {:?} from crate {}", v, name))?;
+ registry.remove_owners(&name, &v).with_context(|| {
+ format!(
+ "failed to remove owners from crate `{}` on registry at {}",
+ name,
+ registry.host()
+ )
+ })?;
+ }
+
+ if opts.list {
+ let owners = registry.list_owners(&name).with_context(|| {
+ format!(
+ "failed to list owners of crate `{}` on registry at {}",
+ name,
+ registry.host()
+ )
+ })?;
+ for owner in owners.iter() {
+ drop_print!(config, "{}", owner.login);
+ match (owner.name.as_ref(), owner.email.as_ref()) {
+ (Some(name), Some(email)) => drop_println!(config, " ({} <{}>)", name, email),
+ (Some(s), None) | (None, Some(s)) => drop_println!(config, " ({})", s),
+ (None, None) => drop_println!(config),
+ }
+ }
+ }
+
+ Ok(())
+}
diff --git a/src/tools/cargo/src/cargo/ops/registry/publish.rs b/src/tools/cargo/src/cargo/ops/registry/publish.rs
new file mode 100644
index 000000000..7f4fbbae2
--- /dev/null
+++ b/src/tools/cargo/src/cargo/ops/registry/publish.rs
@@ -0,0 +1,461 @@
+//! Interacts with the registry [publish API][1].
+//!
+//! [1]: https://doc.rust-lang.org/nightly/cargo/reference/registry-web-api.html#publish
+
+use std::collections::BTreeMap;
+use std::collections::HashSet;
+use std::fs::File;
+use std::time::Duration;
+
+use anyhow::bail;
+use anyhow::Context as _;
+use cargo_util::paths;
+use crates_io::NewCrate;
+use crates_io::NewCrateDependency;
+use crates_io::Registry;
+
+use crate::core::dependency::DepKind;
+use crate::core::manifest::ManifestMetadata;
+use crate::core::resolver::CliFeatures;
+use crate::core::Dependency;
+use crate::core::Package;
+use crate::core::QueryKind;
+use crate::core::SourceId;
+use crate::core::Workspace;
+use crate::ops;
+use crate::ops::PackageOpts;
+use crate::ops::Packages;
+use crate::sources::SourceConfigMap;
+use crate::sources::CRATES_IO_REGISTRY;
+use crate::util::auth;
+use crate::util::auth::Secret;
+use crate::util::config::JobsConfig;
+use crate::util::Progress;
+use crate::util::ProgressStyle;
+use crate::CargoResult;
+use crate::Config;
+
+use super::super::check_dep_has_version;
+
+pub struct PublishOpts<'cfg> {
+ pub config: &'cfg Config,
+ pub token: Option<Secret<String>>,
+ pub index: Option<String>,
+ pub verify: bool,
+ pub allow_dirty: bool,
+ pub jobs: Option<JobsConfig>,
+ pub keep_going: bool,
+ pub to_publish: ops::Packages,
+ pub targets: Vec<String>,
+ pub dry_run: bool,
+ pub registry: Option<String>,
+ pub cli_features: CliFeatures,
+}
+
+pub fn publish(ws: &Workspace<'_>, opts: &PublishOpts<'_>) -> CargoResult<()> {
+ let specs = opts.to_publish.to_package_id_specs(ws)?;
+ if specs.len() > 1 {
+ bail!("the `-p` argument must be specified to select a single package to publish")
+ }
+ if Packages::Default == opts.to_publish && ws.is_virtual() {
+ bail!("the `-p` argument must be specified in the root of a virtual workspace")
+ }
+ let member_ids = ws.members().map(|p| p.package_id());
+ // Check that the spec matches exactly one member.
+ specs[0].query(member_ids)?;
+ let mut pkgs = ws.members_with_features(&specs, &opts.cli_features)?;
+ // In `members_with_features_old`, it will add "current" package (determined by the cwd)
+ // So we need filter
+ pkgs = pkgs
+ .into_iter()
+ .filter(|(m, _)| specs.iter().any(|spec| spec.matches(m.package_id())))
+ .collect();
+ // Double check. It is safe theoretically, unless logic has updated.
+ assert_eq!(pkgs.len(), 1);
+
+ let (pkg, cli_features) = pkgs.pop().unwrap();
+
+ let mut publish_registry = opts.registry.clone();
+ if let Some(ref allowed_registries) = *pkg.publish() {
+ if publish_registry.is_none() && allowed_registries.len() == 1 {
+ // If there is only one allowed registry, push to that one directly,
+ // even though there is no registry specified in the command.
+ let default_registry = &allowed_registries[0];
+ if default_registry != CRATES_IO_REGISTRY {
+ // Don't change the registry for crates.io and don't warn the user.
+ // crates.io will be defaulted even without this.
+ opts.config.shell().note(&format!(
+ "Found `{}` as only allowed registry. Publishing to it automatically.",
+ default_registry
+ ))?;
+ publish_registry = Some(default_registry.clone());
+ }
+ }
+
+ let reg_name = publish_registry
+ .clone()
+ .unwrap_or_else(|| CRATES_IO_REGISTRY.to_string());
+ if allowed_registries.is_empty() {
+ bail!(
+ "`{}` cannot be published.\n\
+ `package.publish` is set to `false` or an empty list in Cargo.toml and prevents publishing.",
+ pkg.name(),
+ );
+ } else if !allowed_registries.contains(&reg_name) {
+ bail!(
+ "`{}` cannot be published.\n\
+ The registry `{}` is not listed in the `package.publish` value in Cargo.toml.",
+ pkg.name(),
+ reg_name
+ );
+ }
+ }
+ // This is only used to confirm that we can create a token before we build the package.
+ // This causes the credential provider to be called an extra time, but keeps the same order of errors.
+ let ver = pkg.version().to_string();
+ let mutation = auth::Mutation::PrePublish;
+
+ let (mut registry, reg_ids) = super::registry(
+ opts.config,
+ opts.token.as_ref().map(Secret::as_deref),
+ opts.index.as_deref(),
+ publish_registry.as_deref(),
+ true,
+ Some(mutation).filter(|_| !opts.dry_run),
+ )?;
+ verify_dependencies(pkg, &registry, reg_ids.original)?;
+
+ // Prepare a tarball, with a non-suppressible warning if metadata
+ // is missing since this is being put online.
+ let tarball = ops::package_one(
+ ws,
+ pkg,
+ &PackageOpts {
+ config: opts.config,
+ verify: opts.verify,
+ list: false,
+ check_metadata: true,
+ allow_dirty: opts.allow_dirty,
+ to_package: Packages::Default,
+ targets: opts.targets.clone(),
+ jobs: opts.jobs.clone(),
+ keep_going: opts.keep_going,
+ cli_features,
+ },
+ )?
+ .unwrap();
+
+ if !opts.dry_run {
+ let hash = cargo_util::Sha256::new()
+ .update_file(tarball.file())?
+ .finish_hex();
+ let mutation = Some(auth::Mutation::Publish {
+ name: pkg.name().as_str(),
+ vers: &ver,
+ cksum: &hash,
+ });
+ registry.set_token(Some(auth::auth_token(
+ &opts.config,
+ &reg_ids.original,
+ None,
+ mutation,
+ )?));
+ }
+
+ opts.config
+ .shell()
+ .status("Uploading", pkg.package_id().to_string())?;
+ transmit(
+ opts.config,
+ pkg,
+ tarball.file(),
+ &mut registry,
+ reg_ids.original,
+ opts.dry_run,
+ )?;
+ if !opts.dry_run {
+ const DEFAULT_TIMEOUT: u64 = 60;
+ let timeout = if opts.config.cli_unstable().publish_timeout {
+ let timeout: Option<u64> = opts.config.get("publish.timeout")?;
+ timeout.unwrap_or(DEFAULT_TIMEOUT)
+ } else {
+ DEFAULT_TIMEOUT
+ };
+ if 0 < timeout {
+ let timeout = Duration::from_secs(timeout);
+ wait_for_publish(opts.config, reg_ids.original, pkg, timeout)?;
+ }
+ }
+
+ Ok(())
+}
+
+fn wait_for_publish(
+ config: &Config,
+ registry_src: SourceId,
+ pkg: &Package,
+ timeout: Duration,
+) -> CargoResult<()> {
+ let version_req = format!("={}", pkg.version());
+ let mut source = SourceConfigMap::empty(config)?.load(registry_src, &HashSet::new())?;
+ // Disable the source's built-in progress bars. Repeatedly showing a bunch
+ // of independent progress bars can be a little confusing. There is an
+ // overall progress bar managed here.
+ source.set_quiet(true);
+ let source_description = source.source_id().to_string();
+ let query = Dependency::parse(pkg.name(), Some(&version_req), registry_src)?;
+
+ let now = std::time::Instant::now();
+ let sleep_time = Duration::from_secs(1);
+ let max = timeout.as_secs() as usize;
+ // Short does not include the registry name.
+ let short_pkg_description = format!("{} v{}", pkg.name(), pkg.version());
+ config.shell().status(
+ "Uploaded",
+ format!("{short_pkg_description} to {source_description}"),
+ )?;
+ config.shell().note(format!(
+ "Waiting for `{short_pkg_description}` to be available at {source_description}.\n\
+ You may press ctrl-c to skip waiting; the crate should be available shortly."
+ ))?;
+ let mut progress = Progress::with_style("Waiting", ProgressStyle::Ratio, config);
+ progress.tick_now(0, max, "")?;
+ let is_available = loop {
+ {
+ let _lock = config.acquire_package_cache_lock()?;
+ // Force re-fetching the source
+ //
+ // As pulling from a git source is expensive, we track when we've done it within the
+ // process to only do it once, but we are one of the rare cases that needs to do it
+ // multiple times
+ config
+ .updated_sources()
+ .remove(&source.replaced_source_id());
+ source.invalidate_cache();
+ let summaries = loop {
+ // Exact to avoid returning all for path/git
+ match source.query_vec(&query, QueryKind::Exact) {
+ std::task::Poll::Ready(res) => {
+ break res?;
+ }
+ std::task::Poll::Pending => source.block_until_ready()?,
+ }
+ };
+ if !summaries.is_empty() {
+ break true;
+ }
+ }
+
+ let elapsed = now.elapsed();
+ if timeout < elapsed {
+ config.shell().warn(format!(
+ "timed out waiting for `{short_pkg_description}` to be available in {source_description}",
+ ))?;
+ config.shell().note(
+ "The registry may have a backlog that is delaying making the \
+ crate available. The crate should be available soon.",
+ )?;
+ break false;
+ }
+
+ progress.tick_now(elapsed.as_secs() as usize, max, "")?;
+ std::thread::sleep(sleep_time);
+ };
+ if is_available {
+ config.shell().status(
+ "Published",
+ format!("{short_pkg_description} at {source_description}"),
+ )?;
+ }
+
+ Ok(())
+}
+
+fn verify_dependencies(
+ pkg: &Package,
+ registry: &Registry,
+ registry_src: SourceId,
+) -> CargoResult<()> {
+ for dep in pkg.dependencies().iter() {
+ if check_dep_has_version(dep, true)? {
+ continue;
+ }
+ // TomlManifest::prepare_for_publish will rewrite the dependency
+ // to be just the `version` field.
+ if dep.source_id() != registry_src {
+ if !dep.source_id().is_registry() {
+ // Consider making SourceId::kind a public type that we can
+ // exhaustively match on. Using match can help ensure that
+ // every kind is properly handled.
+ panic!("unexpected source kind for dependency {:?}", dep);
+ }
+ // Block requests to send to crates.io with alt-registry deps.
+ // This extra hostname check is mostly to assist with testing,
+ // but also prevents someone using `--index` to specify
+ // something that points to crates.io.
+ if registry_src.is_crates_io() || registry.host_is_crates_io() {
+ bail!("crates cannot be published to crates.io with dependencies sourced from other\n\
+ registries. `{}` needs to be published to crates.io before publishing this crate.\n\
+ (crate `{}` is pulled from {})",
+ dep.package_name(),
+ dep.package_name(),
+ dep.source_id());
+ }
+ }
+ }
+ Ok(())
+}
+
+fn transmit(
+ config: &Config,
+ pkg: &Package,
+ tarball: &File,
+ registry: &mut Registry,
+ registry_id: SourceId,
+ dry_run: bool,
+) -> CargoResult<()> {
+ let deps = pkg
+ .dependencies()
+ .iter()
+ .filter(|dep| {
+ // Skip dev-dependency without version.
+ dep.is_transitive() || dep.specified_req()
+ })
+ .map(|dep| {
+ // If the dependency is from a different registry, then include the
+ // registry in the dependency.
+ let dep_registry_id = match dep.registry_id() {
+ Some(id) => id,
+ None => SourceId::crates_io(config)?,
+ };
+ // In the index and Web API, None means "from the same registry"
+ // whereas in Cargo.toml, it means "from crates.io".
+ let dep_registry = if dep_registry_id != registry_id {
+ Some(dep_registry_id.url().to_string())
+ } else {
+ None
+ };
+
+ Ok(NewCrateDependency {
+ optional: dep.is_optional(),
+ default_features: dep.uses_default_features(),
+ name: dep.package_name().to_string(),
+ features: dep.features().iter().map(|s| s.to_string()).collect(),
+ version_req: dep.version_req().to_string(),
+ target: dep.platform().map(|s| s.to_string()),
+ kind: match dep.kind() {
+ DepKind::Normal => "normal",
+ DepKind::Build => "build",
+ DepKind::Development => "dev",
+ }
+ .to_string(),
+ registry: dep_registry,
+ explicit_name_in_toml: dep.explicit_name_in_toml().map(|s| s.to_string()),
+ })
+ })
+ .collect::<CargoResult<Vec<NewCrateDependency>>>()?;
+ let manifest = pkg.manifest();
+ let ManifestMetadata {
+ ref authors,
+ ref description,
+ ref homepage,
+ ref documentation,
+ ref keywords,
+ ref readme,
+ ref repository,
+ ref license,
+ ref license_file,
+ ref categories,
+ ref badges,
+ ref links,
+ ref rust_version,
+ } = *manifest.metadata();
+ let readme_content = readme
+ .as_ref()
+ .map(|readme| {
+ paths::read(&pkg.root().join(readme))
+ .with_context(|| format!("failed to read `readme` file for package `{}`", pkg))
+ })
+ .transpose()?;
+ if let Some(ref file) = *license_file {
+ if !pkg.root().join(file).exists() {
+ bail!("the license file `{}` does not exist", file)
+ }
+ }
+
+ // Do not upload if performing a dry run
+ if dry_run {
+ config.shell().warn("aborting upload due to dry run")?;
+ return Ok(());
+ }
+
+ let string_features = match manifest.original().features() {
+ Some(features) => features
+ .iter()
+ .map(|(feat, values)| {
+ (
+ feat.to_string(),
+ values.iter().map(|fv| fv.to_string()).collect(),
+ )
+ })
+ .collect::<BTreeMap<String, Vec<String>>>(),
+ None => BTreeMap::new(),
+ };
+
+ let warnings = registry
+ .publish(
+ &NewCrate {
+ name: pkg.name().to_string(),
+ vers: pkg.version().to_string(),
+ deps,
+ features: string_features,
+ authors: authors.clone(),
+ description: description.clone(),
+ homepage: homepage.clone(),
+ documentation: documentation.clone(),
+ keywords: keywords.clone(),
+ categories: categories.clone(),
+ readme: readme_content,
+ readme_file: readme.clone(),
+ repository: repository.clone(),
+ license: license.clone(),
+ license_file: license_file.clone(),
+ badges: badges.clone(),
+ links: links.clone(),
+ rust_version: rust_version.clone(),
+ },
+ tarball,
+ )
+ .with_context(|| format!("failed to publish to registry at {}", registry.host()))?;
+
+ if !warnings.invalid_categories.is_empty() {
+ let msg = format!(
+ "the following are not valid category slugs and were \
+ ignored: {}. Please see https://crates.io/category_slugs \
+ for the list of all category slugs. \
+ ",
+ warnings.invalid_categories.join(", ")
+ );
+ config.shell().warn(&msg)?;
+ }
+
+ if !warnings.invalid_badges.is_empty() {
+ let msg = format!(
+ "the following are not valid badges and were ignored: {}. \
+ Either the badge type specified is unknown or a required \
+ attribute is missing. Please see \
+ https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata \
+ for valid badge types and their required attributes.",
+ warnings.invalid_badges.join(", ")
+ );
+ config.shell().warn(&msg)?;
+ }
+
+ if !warnings.other.is_empty() {
+ for msg in warnings.other {
+ config.shell().warn(&msg)?;
+ }
+ }
+
+ Ok(())
+}
diff --git a/src/tools/cargo/src/cargo/ops/registry/search.rs b/src/tools/cargo/src/cargo/ops/registry/search.rs
new file mode 100644
index 000000000..5e01ea98f
--- /dev/null
+++ b/src/tools/cargo/src/cargo/ops/registry/search.rs
@@ -0,0 +1,95 @@
+//! Interacts with the registry [search API][1].
+//!
+//! [1]: https://doc.rust-lang.org/nightly/cargo/reference/registry-web-api.html#search
+
+use std::cmp;
+use std::iter::repeat;
+
+use anyhow::Context as _;
+use termcolor::Color;
+use termcolor::ColorSpec;
+use url::Url;
+
+use crate::util::truncate_with_ellipsis;
+use crate::CargoResult;
+use crate::Config;
+
+pub fn search(
+ query: &str,
+ config: &Config,
+ index: Option<String>,
+ limit: u32,
+ reg: Option<String>,
+) -> CargoResult<()> {
+ let (mut registry, source_ids) =
+ super::registry(config, None, index.as_deref(), reg.as_deref(), false, None)?;
+ let (crates, total_crates) = registry.search(query, limit).with_context(|| {
+ format!(
+ "failed to retrieve search results from the registry at {}",
+ registry.host()
+ )
+ })?;
+
+ let names = crates
+ .iter()
+ .map(|krate| format!("{} = \"{}\"", krate.name, krate.max_version))
+ .collect::<Vec<String>>();
+
+ let description_margin = names.iter().map(|s| s.len() + 4).max().unwrap_or_default();
+
+ let description_length = cmp::max(80, 128 - description_margin);
+
+ let descriptions = crates.iter().map(|krate| {
+ krate
+ .description
+ .as_ref()
+ .map(|desc| truncate_with_ellipsis(&desc.replace("\n", " "), description_length))
+ });
+
+ for (name, description) in names.into_iter().zip(descriptions) {
+ let line = match description {
+ Some(desc) => {
+ let space = repeat(' ')
+ .take(description_margin - name.len())
+ .collect::<String>();
+ name + &space + "# " + &desc
+ }
+ None => name,
+ };
+ let mut fragments = line.split(query).peekable();
+ while let Some(fragment) = fragments.next() {
+ let _ = config.shell().write_stdout(fragment, &ColorSpec::new());
+ if fragments.peek().is_some() {
+ let _ = config.shell().write_stdout(
+ query,
+ &ColorSpec::new().set_bold(true).set_fg(Some(Color::Green)),
+ );
+ }
+ }
+ let _ = config.shell().write_stdout("\n", &ColorSpec::new());
+ }
+
+ let search_max_limit = 100;
+ if total_crates > limit && limit < search_max_limit {
+ let _ = config.shell().write_stdout(
+ format_args!(
+ "... and {} crates more (use --limit N to see more)\n",
+ total_crates - limit
+ ),
+ &ColorSpec::new(),
+ );
+ } else if total_crates > limit && limit >= search_max_limit {
+ let extra = if source_ids.original.is_crates_io() {
+ let url = Url::parse_with_params("https://crates.io/search", &[("q", query)])?;
+ format!(" (go to {url} to see more)")
+ } else {
+ String::new()
+ };
+ let _ = config.shell().write_stdout(
+ format_args!("... and {} crates more{}\n", total_crates - limit, extra),
+ &ColorSpec::new(),
+ );
+ }
+
+ Ok(())
+}
diff --git a/src/tools/cargo/src/cargo/ops/registry/yank.rs b/src/tools/cargo/src/cargo/ops/registry/yank.rs
new file mode 100644
index 000000000..7f087570a
--- /dev/null
+++ b/src/tools/cargo/src/cargo/ops/registry/yank.rs
@@ -0,0 +1,76 @@
+//! Interacts with the registry [yank] and [unyank] API.
+//!
+//! [yank]: https://doc.rust-lang.org/nightly/cargo/reference/registry-web-api.html#yank
+//! [unyank]: https://doc.rust-lang.org/nightly/cargo/reference/registry-web-api.html#unyank
+
+use anyhow::bail;
+use anyhow::Context as _;
+
+use crate::core::Workspace;
+use crate::util::auth;
+use crate::util::auth::Secret;
+use crate::util::config::Config;
+use crate::util::errors::CargoResult;
+use crate::util::important_paths::find_root_manifest_for_wd;
+
+pub fn yank(
+ config: &Config,
+ krate: Option<String>,
+ version: Option<String>,
+ token: Option<Secret<String>>,
+ index: Option<String>,
+ undo: bool,
+ reg: Option<String>,
+) -> CargoResult<()> {
+ let name = match krate {
+ Some(name) => name,
+ None => {
+ let manifest_path = find_root_manifest_for_wd(config.cwd())?;
+ let ws = Workspace::new(&manifest_path, config)?;
+ ws.current()?.package_id().name().to_string()
+ }
+ };
+ let version = match version {
+ Some(v) => v,
+ None => bail!("a version must be specified to yank"),
+ };
+
+ let message = if undo {
+ auth::Mutation::Unyank {
+ name: &name,
+ vers: &version,
+ }
+ } else {
+ auth::Mutation::Yank {
+ name: &name,
+ vers: &version,
+ }
+ };
+
+ let (mut registry, _) = super::registry(
+ config,
+ token.as_ref().map(Secret::as_deref),
+ index.as_deref(),
+ reg.as_deref(),
+ true,
+ Some(message),
+ )?;
+
+ let package_spec = format!("{}@{}", name, version);
+ if undo {
+ config.shell().status("Unyank", package_spec)?;
+ registry.unyank(&name, &version).with_context(|| {
+ format!(
+ "failed to undo a yank from the registry at {}",
+ registry.host()
+ )
+ })?;
+ } else {
+ config.shell().status("Yank", package_spec)?;
+ registry
+ .yank(&name, &version)
+ .with_context(|| format!("failed to yank from the registry at {}", registry.host()))?;
+ }
+
+ Ok(())
+}
diff --git a/src/tools/cargo/src/cargo/sources/config.rs b/src/tools/cargo/src/cargo/sources/config.rs
index 5d5a4e8db..4097567bb 100644
--- a/src/tools/cargo/src/cargo/sources/config.rs
+++ b/src/tools/cargo/src/cargo/sources/config.rs
@@ -14,7 +14,9 @@ use log::debug;
use std::collections::{HashMap, HashSet};
use url::Url;
-/// Represents the entire `[source]` table in Cargo configuration.
+/// Represents the entire [`[source]` replacement table][1] in Cargo configuration.
+///
+/// [1]: https://doc.rust-lang.org/nightly/cargo/reference/config.html#source
#[derive(Clone)]
pub struct SourceConfigMap<'cfg> {
/// Mapping of source name to the toml configuration.
diff --git a/src/tools/cargo/src/cargo/sources/git/known_hosts.rs b/src/tools/cargo/src/cargo/sources/git/known_hosts.rs
index 9a623151e..7b013f99c 100644
--- a/src/tools/cargo/src/cargo/sources/git/known_hosts.rs
+++ b/src/tools/cargo/src/cargo/sources/git/known_hosts.rs
@@ -1,5 +1,8 @@
//! SSH host key validation support.
//!
+//! The only public item in this module is [`certificate_check`],
+//! which provides a callback to [`git2::RemoteCallbacks::certificate_check`].
+//!
//! A primary goal with this implementation is to provide user-friendly error
//! messages, guiding them to understand the issue and how to resolve it.
//!
@@ -408,7 +411,7 @@ fn check_ssh_known_hosts_loaded(
// fingerprints (see FingerprintHash ssh config option). Here we only
// support SHA256.
let mut remote_fingerprint = cargo_util::Sha256::new();
- remote_fingerprint.update(remote_host_key.clone());
+ remote_fingerprint.update(remote_host_key);
let remote_fingerprint = STANDARD_NO_PAD.encode(remote_fingerprint.finish());
let remote_host_key_encoded = STANDARD.encode(remote_host_key);
diff --git a/src/tools/cargo/src/cargo/sources/git/mod.rs b/src/tools/cargo/src/cargo/sources/git/mod.rs
index 47827f267..5d9d2886e 100644
--- a/src/tools/cargo/src/cargo/sources/git/mod.rs
+++ b/src/tools/cargo/src/cargo/sources/git/mod.rs
@@ -1,3 +1,12 @@
+//! Home of the [`GitSource`].
+//!
+//! Apparently, the most important type in this module is [`GitSource`].
+//! [`utils`] provides libgit2 utilities like fetch and checkout, whereas
+//! [`oxide`] is the couterpart for gitoxide integration. [`known_hosts`]
+//! is the mitigation of [CVE-2022-46176].
+//!
+//! [CVE-2022-46176]: https://blog.rust-lang.org/2023/01/10/cve-2022-46176.html
+
pub use self::source::GitSource;
pub use self::utils::{fetch, GitCheckout, GitDatabase, GitRemote};
mod known_hosts;
@@ -5,6 +14,7 @@ mod oxide;
mod source;
mod utils;
+/// For `-Zgitoxide` integration.
pub mod fetch {
use crate::core::features::GitoxideFeatures;
use crate::Config;
diff --git a/src/tools/cargo/src/cargo/sources/git/oxide.rs b/src/tools/cargo/src/cargo/sources/git/oxide.rs
index c8d0a4ecd..e86c63e8e 100644
--- a/src/tools/cargo/src/cargo/sources/git/oxide.rs
+++ b/src/tools/cargo/src/cargo/sources/git/oxide.rs
@@ -1,7 +1,7 @@
//! This module contains all code sporting `gitoxide` for operations on `git` repositories and it mirrors
//! `utils` closely for now. One day it can be renamed into `utils` once `git2` isn't required anymore.
-use crate::ops::HttpTimeout;
+use crate::util::network::http::HttpTimeout;
use crate::util::{human_readable_bytes, network, MetricsCounter, Progress};
use crate::{CargoResult, Config};
use cargo_util::paths;
@@ -353,6 +353,8 @@ pub fn cargo_config_to_gitoxide_overrides(config: &Config) -> CargoResult<Vec<BS
Ok(values)
}
+/// Reinitializes a given Git repository. This is useful when a Git repoistory
+/// seems corrupted and we want to start over.
pub fn reinitialize(git_dir: &Path) -> CargoResult<()> {
fn init(path: &Path, bare: bool) -> CargoResult<()> {
let mut opts = git2::RepositoryInitOptions::new();
diff --git a/src/tools/cargo/src/cargo/sources/git/source.rs b/src/tools/cargo/src/cargo/sources/git/source.rs
index 4cdb8983b..b021d23a0 100644
--- a/src/tools/cargo/src/cargo/sources/git/source.rs
+++ b/src/tools/cargo/src/cargo/sources/git/source.rs
@@ -1,3 +1,5 @@
+//! See [GitSource].
+
use crate::core::source::{MaybePackage, QueryKind, Source, SourceId};
use crate::core::GitReference;
use crate::core::{Dependency, Package, PackageId, Summary};
@@ -13,18 +15,71 @@ use std::fmt::{self, Debug, Formatter};
use std::task::Poll;
use url::Url;
+/// `GitSource` contains one or more packages gathering from a Git repository.
+/// Under the hood it uses [`PathSource`] to discover packages inside the
+/// repository.
+///
+/// ## Filesystem layout
+///
+/// During a successful `GitSource` download, at least two Git repositories are
+/// created: one is the shared Git database of this remote, and the other is the
+/// Git checkout to a specific revision, which contains the actual files to be
+/// compiled. Multiple checkouts can be cloned from a single Git database.
+///
+/// Those repositories are located at Cargo's Git cache directory
+/// `$CARGO_HOME/git`. The file tree of the cache directory roughly looks like:
+///
+/// ```text
+/// $CARGO_HOME/git/
+/// ├── checkouts/
+/// │ ├── gimli-a0d193bd15a5ed96/
+/// │ │ ├── 8e73ef0/ # Git short ID for a certain revision
+/// │ │ ├── a2a4b78/
+/// │ │ └── e33d1ac/
+/// │ ├── log-c58e1db3de7c154d-shallow/
+/// │ │ └── 11eda98/
+/// └── db/
+/// ├── gimli-a0d193bd15a5ed96/
+/// └── log-c58e1db3de7c154d-shallow/
+/// ```
+///
+/// For more on Git cache directory, see ["Cargo Home"] in The Cargo Book.
+///
+/// For more on the directory format `<pkg>-<hash>[-shallow]`, see [`ident`]
+/// and [`ident_shallow`].
+///
+/// ## Locked to a revision
+///
+/// Once a `GitSource` is fetched, it will resolve to a specific commit revision.
+/// This is often mentioned as "locked revision" (`locked_rev`) throughout the
+/// codebase. The revision is written into `Cargo.lock`. This is essential since
+/// we want to ensure a package can compiles with the same set of files when
+/// a `Cargo.lock` is present. With the `locked_rev` provided, `GitSource` can
+/// precisely fetch the same revision from the Git repository.
+///
+/// ["Cargo Home"]: https://doc.rust-lang.org/nightly/cargo/guide/cargo-home.html#directories
pub struct GitSource<'cfg> {
+ /// The git remote which we're going to fetch from.
remote: GitRemote,
+ /// The Git reference from the manifest file.
manifest_reference: GitReference,
+ /// The revision which a git source is locked to.
+ /// This is expected to be set after the Git repository is fetched.
locked_rev: Option<git2::Oid>,
+ /// The unique identifier of this source.
source_id: SourceId,
+ /// The underlying path source to discover packages inside the Git repository.
path_source: Option<PathSource<'cfg>>,
+ /// The identifer of this source for Cargo's Git cache directory.
+ /// See [`ident`] for more.
ident: String,
config: &'cfg Config,
+ /// Disables status messages.
quiet: bool,
}
impl<'cfg> GitSource<'cfg> {
+ /// Creates a git source for the given [`SourceId`].
pub fn new(source_id: SourceId, config: &'cfg Config) -> CargoResult<GitSource<'cfg>> {
assert!(source_id.is_git(), "id is not git, id={}", source_id);
@@ -59,10 +114,14 @@ impl<'cfg> GitSource<'cfg> {
Ok(source)
}
+ /// Gets the remote repository URL.
pub fn url(&self) -> &Url {
self.remote.url()
}
+ /// Returns the packages discovered by this source. It may fetch the Git
+ /// repository as well as walk the filesystem if package informations
+ /// haven't yet updated.
pub fn read_packages(&mut self) -> CargoResult<Vec<Package>> {
if self.path_source.is_none() {
self.invalidate_cache();
@@ -72,7 +131,8 @@ impl<'cfg> GitSource<'cfg> {
}
}
-/// Create an identifier from a URL, essentially turning `proto://host/path/repo` into `repo-<hash-of-url>`.
+/// 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()
@@ -86,10 +146,12 @@ 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`.
+/// 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.
+/// 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 {
@@ -217,8 +279,7 @@ impl<'cfg> Source for GitSource<'cfg> {
.join("checkouts")
.join(&self.ident)
.join(short_id.as_str());
- let parent_remote_url = self.url();
- db.copy_to(actual_rev, &checkout_path, self.config, parent_remote_url)?;
+ db.copy_to(actual_rev, &checkout_path, self.config)?;
let source_id = self.source_id.with_precise(Some(actual_rev.to_string()));
let path_source = PathSource::new_recursive(&checkout_path, source_id, self.config);
diff --git a/src/tools/cargo/src/cargo/sources/git/utils.rs b/src/tools/cargo/src/cargo/sources/git/utils.rs
index c14d1daf3..0c7ce8b64 100644
--- a/src/tools/cargo/src/cargo/sources/git/utils.rs
+++ b/src/tools/cargo/src/cargo/sources/git/utils.rs
@@ -23,6 +23,10 @@ use std::sync::atomic::{AtomicBool, Ordering};
use std::time::{Duration, Instant};
use url::Url;
+/// A file indicates that if present, `git reset` has been done and a repo
+/// checkout is ready to go. See [`GitCheckout::reset`] for why we need this.
+const CHECKOUT_READY_LOCK: &str = ".cargo-ok";
+
fn serialize_str<T, S>(t: &T, s: S) -> Result<S::Ok, S::Error>
where
T: fmt::Display,
@@ -31,60 +35,72 @@ where
s.collect_str(t)
}
+/// A short abbreviated OID.
+///
+/// Exists for avoiding extra allocations in [`GitDatabase::to_short_id`].
pub struct GitShortID(git2::Buf);
impl GitShortID {
+ /// Views the short ID as a `str`.
pub fn as_str(&self) -> &str {
self.0.as_str().unwrap()
}
}
-/// `GitRemote` represents a remote repository. It gets cloned into a local
-/// `GitDatabase`.
+/// A remote repository. It gets cloned into a local [`GitDatabase`].
#[derive(PartialEq, Clone, Debug, Serialize)]
pub struct GitRemote {
+ /// URL to a remote repository.
#[serde(serialize_with = "serialize_str")]
url: Url,
}
-/// `GitDatabase` is a local clone of a remote repository's database. Multiple
-/// `GitCheckouts` can be cloned from this `GitDatabase`.
-#[derive(Serialize)]
+/// A local clone of a remote repository's database. Multiple [`GitCheckout`]s
+/// can be cloned from a single [`GitDatabase`].
pub struct GitDatabase {
+ /// The remote repository where this database is fetched from.
remote: GitRemote,
+ /// Path to the root of the underlying Git repository on the local filesystem.
path: PathBuf,
- #[serde(skip_serializing)]
+ /// Underlying Git repository instance for this database.
repo: git2::Repository,
}
-/// `GitCheckout` is a local checkout of a particular revision. Calling
-/// `clone_into` with a reference will resolve the reference into a revision,
-/// and return an `anyhow::Error` if no revision for that reference was found.
-#[derive(Serialize)]
+/// A local checkout of a particular revision from a [`GitDatabase`].
pub struct GitCheckout<'a> {
+ /// The git database where this checkout is cloned from.
database: &'a GitDatabase,
- location: PathBuf,
- #[serde(serialize_with = "serialize_str")]
+ /// Path to the root of the underlying Git repository on the local filesystem.
+ path: PathBuf,
+ /// The git revision this checkout is for.
revision: git2::Oid,
- #[serde(skip_serializing)]
+ /// Underlying Git repository instance for this checkout.
repo: git2::Repository,
}
-// Implementations
-
impl GitRemote {
+ /// Creates an instance for a remote repository URL.
pub fn new(url: &Url) -> GitRemote {
GitRemote { url: url.clone() }
}
+ /// Gets the remote repository URL.
pub fn url(&self) -> &Url {
&self.url
}
- pub fn rev_for(&self, path: &Path, reference: &GitReference) -> CargoResult<git2::Oid> {
- reference.resolve(&self.db_at(path)?.repo)
- }
-
+ /// Fetches and checkouts to a reference or a revision from this remote
+ /// into a local path.
+ ///
+ /// This ensures that it gets the up-to-date commit when a named reference
+ /// is given (tag, branch, refs/*). Thus, network connection is involved.
+ ///
+ /// When `locked_rev` is provided, it takes precedence over `reference`.
+ ///
+ /// If we have a previous instance of [`GitDatabase`] then fetch into that
+ /// 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.
pub fn checkout(
&self,
into: &Path,
@@ -93,10 +109,6 @@ impl GitRemote {
locked_rev: Option<git2::Oid>,
cargo_config: &Config,
) -> CargoResult<(GitDatabase, git2::Oid)> {
- // If we have a previous instance of `GitDatabase` then fetch into that
- // 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 {
@@ -149,6 +161,7 @@ impl GitRemote {
))
}
+ /// Creates a [`GitDatabase`] of this remote at `db_path`.
pub fn db_at(&self, db_path: &Path) -> CargoResult<GitDatabase> {
let repo = git2::Repository::open(db_path)?;
Ok(GitDatabase {
@@ -160,12 +173,12 @@ impl GitRemote {
}
impl GitDatabase {
+ /// Checkouts to a revision at `dest`ination from this database.
pub fn copy_to(
&self,
rev: git2::Oid,
dest: &Path,
cargo_config: &Config,
- parent_remote_url: &Url,
) -> CargoResult<GitCheckout<'_>> {
// If the existing checkout exists, and it is fresh, use it.
// A non-fresh checkout can happen if the checkout operation was
@@ -173,31 +186,35 @@ impl GitDatabase {
// clone is created.
let checkout = match git2::Repository::open(dest)
.ok()
- .map(|repo| GitCheckout::new(dest, self, rev, repo))
+ .map(|repo| GitCheckout::new(self, rev, repo))
.filter(|co| co.is_fresh())
{
Some(co) => co,
None => GitCheckout::clone_into(dest, self, rev, cargo_config)?,
};
- checkout.update_submodules(cargo_config, parent_remote_url)?;
+ checkout.update_submodules(cargo_config)?;
Ok(checkout)
}
+ /// Get a short OID for a `revision`, usually 7 chars or more if ambiguous.
pub fn to_short_id(&self, revision: git2::Oid) -> CargoResult<GitShortID> {
let obj = self.repo.find_object(revision, None)?;
Ok(GitShortID(obj.short_id()?))
}
+ /// Checks if the database contains the object of this `oid`..
pub fn contains(&self, oid: git2::Oid) -> bool {
self.repo.revparse_single(&oid.to_string()).is_ok()
}
+ /// [`GitReference::resolve`]s this reference with this database.
pub fn resolve(&self, r: &GitReference) -> CargoResult<git2::Oid> {
r.resolve(&self.repo)
}
}
impl GitReference {
+ /// Resolves self to an object ID with objects the `repo` currently has.
pub fn resolve(&self, repo: &git2::Repository) -> CargoResult<git2::Oid> {
let id = match self {
// Note that we resolve the named tag here in sync with where it's
@@ -243,20 +260,32 @@ impl GitReference {
}
impl<'a> GitCheckout<'a> {
+ /// Creates an instance of [`GitCheckout`]. This doesn't imply the checkout
+ /// is done. Use [`GitCheckout::is_fresh`] to check.
+ ///
+ /// * The `database` is where this checkout is from.
+ /// * The `repo` will be the checked out Git repoistory.
fn new(
- path: &Path,
database: &'a GitDatabase,
revision: git2::Oid,
repo: git2::Repository,
) -> GitCheckout<'a> {
+ let path = repo.workdir().unwrap_or_else(|| repo.path());
GitCheckout {
- location: path.to_path_buf(),
+ path: path.to_path_buf(),
database,
revision,
repo,
}
}
+ /// Gets the remote repository URL.
+ fn remote_url(&self) -> &Url {
+ &self.database.remote.url()
+ }
+
+ /// Clone a repo for a `revision` into a local path from a `datatabase`.
+ /// This is a filesystem-to-filesystem clone.
fn clone_into(
into: &Path,
database: &'a GitDatabase,
@@ -293,10 +322,12 @@ 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.
+ // `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.
+ //
+ // TODO(git2): remove this when git2 supports shallow clone correctly
if database.repo.is_shallow() {
std::fs::copy(
database.repo.path().join("shallow"),
@@ -308,31 +339,38 @@ impl<'a> GitCheckout<'a> {
})?;
let repo = repo.unwrap();
- let checkout = GitCheckout::new(into, database, revision, repo);
+ let checkout = GitCheckout::new(database, revision, repo);
checkout.reset(config)?;
Ok(checkout)
}
+ /// Checks if the `HEAD` of this checkout points to the expected revision.
fn is_fresh(&self) -> bool {
match self.repo.revparse_single("HEAD") {
Ok(ref head) if head.id() == self.revision => {
// See comments in reset() for why we check this
- self.location.join(".cargo-ok").exists()
+ self.path.join(CHECKOUT_READY_LOCK).exists()
}
_ => false,
}
}
+ /// Similar to [`reset()`]. This roughly performs `git reset --hard` to the
+ /// revision of this checkout, with additional interrupt protection by a
+ /// dummy file [`CHECKOUT_READY_LOCK`].
+ ///
+ /// If we're interrupted while performing a `git reset` (e.g., we die
+ /// because of a signal) Cargo needs to be sure to try to check out this
+ /// repo again on the next go-round.
+ ///
+ /// To enable this we have a dummy file in our checkout, [`.cargo-ok`],
+ /// which if present means that the repo has been successfully reset and is
+ /// ready to go. Hence if we start to do a reset, we make sure this file
+ /// *doesn't* exist, and then once we're done we create the file.
+ ///
+ /// [`.cargo-ok`]: CHECKOUT_READY_LOCK
fn reset(&self, config: &Config) -> CargoResult<()> {
- // If we're interrupted while performing this reset (e.g., we die because
- // of a signal) Cargo needs to be sure to try to check out this repo
- // again on the next go-round.
- //
- // To enable this we have a dummy file in our checkout, .cargo-ok, which
- // if present means that the repo has been successfully reset and is
- // ready to go. Hence if we start to do a reset, we make sure this file
- // *doesn't* exist, and then once we're done we create the file.
- let ok_file = self.location.join(".cargo-ok");
+ let ok_file = self.path.join(CHECKOUT_READY_LOCK);
let _ = paths::remove_file(&ok_file);
info!("reset {} to {}", self.repo.path().display(), self.revision);
@@ -347,13 +385,20 @@ impl<'a> GitCheckout<'a> {
Ok(())
}
- fn update_submodules(&self, cargo_config: &Config, parent_remote_url: &Url) -> CargoResult<()> {
- return update_submodules(&self.repo, cargo_config, parent_remote_url);
+ /// Like `git submodule update --recursive` but for this git checkout.
+ ///
+ /// This function respects `submodule.<name>.update = none`[^1] git config.
+ /// Submodules set to `none` won't be fetched.
+ ///
+ /// [^1]: <https://git-scm.com/docs/git-submodule#Documentation/git-submodule.txt-none>
+ fn update_submodules(&self, cargo_config: &Config) -> CargoResult<()> {
+ return update_submodules(&self.repo, cargo_config, self.remote_url().as_str());
+ /// Recusive helper for [`GitCheckout::update_submodules`].
fn update_submodules(
repo: &git2::Repository,
cargo_config: &Config,
- parent_remote_url: &Url,
+ parent_remote_url: &str,
) -> CargoResult<()> {
debug!("update submodules for: {:?}", repo.workdir().unwrap());
@@ -370,11 +415,12 @@ impl<'a> GitCheckout<'a> {
Ok(())
}
+ /// Update a single Git submodule, and recurse into its submodules.
fn update_submodule(
parent: &git2::Repository,
child: &mut git2::Submodule<'_>,
cargo_config: &Config,
- parent_remote_url: &Url,
+ parent_remote_url: &str,
) -> CargoResult<()> {
child.init(false)?;
@@ -394,31 +440,7 @@ impl<'a> GitCheckout<'a> {
return Ok(());
}
- // Git only assumes a URL is a relative path if it starts with `./` or `../`.
- // See [`git submodule add`] documentation.
- //
- // [`git submodule add`]: https://git-scm.com/docs/git-submodule
- let url = if child_url_str.starts_with("./") || child_url_str.starts_with("../") {
- let mut new_parent_remote_url = parent_remote_url.clone();
-
- let mut new_path = Cow::from(parent_remote_url.path());
- if !new_path.ends_with('/') {
- new_path.to_mut().push('/');
- }
- new_parent_remote_url.set_path(&new_path);
-
- match new_parent_remote_url.join(child_url_str) {
- Ok(x) => x.to_string(),
- Err(err) => Err(err).with_context(|| {
- format!(
- "failed to parse relative child submodule url `{}` using parent base url `{}`",
- child_url_str, new_parent_remote_url
- )
- })?,
- }
- } else {
- child_url_str.to_string()
- };
+ let child_remote_url = absolute_submodule_url(parent_remote_url, child_url_str)?;
// A submodule which is listed in .gitmodules but not actually
// checked out will not have a head id, so we should ignore it.
@@ -438,7 +460,7 @@ impl<'a> GitCheckout<'a> {
let mut repo = match head_and_repo {
Ok((head, repo)) => {
if child.head_id() == head {
- return update_submodules(&repo, cargo_config, parent_remote_url);
+ return update_submodules(&repo, cargo_config, &child_remote_url);
}
repo
}
@@ -452,29 +474,78 @@ impl<'a> GitCheckout<'a> {
let reference = GitReference::Rev(head.to_string());
cargo_config
.shell()
- .status("Updating", format!("git submodule `{}`", url))?;
+ .status("Updating", format!("git submodule `{child_remote_url}`"))?;
fetch(
&mut repo,
- &url,
+ &child_remote_url,
&reference,
cargo_config,
RemoteKind::GitDependency,
)
.with_context(|| {
- format!(
- "failed to fetch submodule `{}` from {}",
- child.name().unwrap_or(""),
- url
- )
+ let name = child.name().unwrap_or("");
+ format!("failed to fetch submodule `{name}` from {child_remote_url}",)
})?;
let obj = repo.find_object(head, None)?;
reset(&repo, &obj, cargo_config)?;
- update_submodules(&repo, cargo_config, parent_remote_url)
+ update_submodules(&repo, cargo_config, &child_remote_url)
}
}
}
+/// Constructs an absolute URL for a child submodule URL with its parent base URL.
+///
+/// Git only assumes a submodule URL is a relative path if it starts with `./`
+/// or `../` [^1]. To fetch the correct repo, we need to construct an absolute
+/// submodule URL.
+///
+/// At this moment it comes with some limitations:
+///
+/// * GitHub doesn't accept non-normalized URLs with relative paths.
+/// (`ssh://git@github.com/rust-lang/cargo.git/relative/..` is invalid)
+/// * `url` crate cannot parse SCP-like URLs.
+/// (`git@github.com:rust-lang/cargo.git` is not a valid WHATWG URL)
+///
+/// To overcome these, this patch always tries [`Url::parse`] first to normalize
+/// the path. If it couldn't, append the relative path as the last resort and
+/// pray the remote git service supports non-normalized URLs.
+///
+/// See also rust-lang/cargo#12404 and rust-lang/cargo#12295.
+///
+/// [^1]: <https://git-scm.com/docs/git-submodule>
+fn absolute_submodule_url<'s>(base_url: &str, submodule_url: &'s str) -> CargoResult<Cow<'s, str>> {
+ let absolute_url = if ["./", "../"].iter().any(|p| submodule_url.starts_with(p)) {
+ match Url::parse(base_url) {
+ Ok(mut base_url) => {
+ let path = base_url.path();
+ if !path.ends_with('/') {
+ base_url.set_path(&format!("{path}/"));
+ }
+ let absolute_url = base_url.join(submodule_url).with_context(|| {
+ format!(
+ "failed to parse relative child submodule url `{submodule_url}` \
+ using parent base url `{base_url}`"
+ )
+ })?;
+ Cow::from(absolute_url.to_string())
+ }
+ Err(_) => {
+ let mut absolute_url = base_url.to_string();
+ if !absolute_url.ends_with('/') {
+ absolute_url.push('/');
+ }
+ absolute_url.push_str(submodule_url);
+ Cow::from(absolute_url)
+ }
+ }
+ } else {
+ Cow::from(submodule_url)
+ };
+
+ Ok(absolute_url)
+}
+
/// Prepare the authentication callbacks for cloning a git repository.
///
/// The main purpose of this function is to construct the "authentication
@@ -745,6 +816,9 @@ where
Err(err)
}
+/// `git reset --hard` to the given `obj` for the `repo`.
+///
+/// The `obj` is a commit-ish to which the head should be moved.
fn reset(repo: &git2::Repository, obj: &git2::Object<'_>, config: &Config) -> CargoResult<()> {
let mut pb = Progress::new("Checkout", config);
let mut opts = git2::build::CheckoutBuilder::new();
@@ -757,6 +831,14 @@ fn reset(repo: &git2::Repository, obj: &git2::Object<'_>, config: &Config) -> Ca
Ok(())
}
+/// Prepares the callbacks for fetching a git repository.
+///
+/// The main purpose of this function is to construct everything before a fetch.
+/// This will attempt to setup a progress bar, the authentication for git,
+/// ssh known hosts check, and the network retry mechanism.
+///
+/// The callback is provided a fetch options, which can be used by the actual
+/// git fetch.
pub fn with_fetch_options(
git_config: &git2::Config,
url: &str,
@@ -831,12 +913,22 @@ 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.
+/// Attempts to fetch the given git `reference` for a Git repository.
+///
+/// This is the main entry for git clone/fetch. It does the followings:
+///
+/// * Turns [`GitReference`] into refspecs accordingly.
+/// * Dispatches `git fetch` using libgit2, gitoxide, or git CLI.
+///
+/// The `remote_url` argument is the git remote URL where we want to fetch from.
+///
+/// The `remote_kind` argument is a thing for [`-Zgitoxide`] shallow clones
+/// at this time. It could be extended when libgit2 supports shallow clones.
+///
+/// [`-Zgitoxide`]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#gitoxide
pub fn fetch(
repo: &mut git2::Repository,
- orig_url: &str,
+ remote_url: &str,
reference: &GitReference,
config: &Config,
remote_kind: RemoteKind,
@@ -853,9 +945,7 @@ pub fn fetch(
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.
- let oid_to_fetch = match github_fast_path(repo, orig_url, reference, config) {
+ let oid_to_fetch = match github_fast_path(repo, remote_url, reference, config) {
Ok(FastPathRev::UpToDate) => return Ok(()),
Ok(FastPathRev::NeedsFetch(rev)) => Some(rev),
Ok(FastPathRev::Indeterminate) => None,
@@ -865,10 +955,6 @@ pub fn fetch(
}
};
- // We reuse repositories quite a lot, so before we go through and update the
- // repo check to see if it's a little too old and could benefit from a gc.
- // In theory this shouldn't be too expensive compared to the network
- // request we're about to issue.
maybe_gc_repo(repo, config)?;
clean_repo_temp_files(repo);
@@ -921,15 +1007,10 @@ pub fn fetch(
}
}
- // Unfortunately `libgit2` is notably lacking in the realm of authentication
- // when compared to the `git` command line. As a result, allow an escape
- // hatch for users that would prefer to use `git`-the-CLI for fetching
- // repositories instead of `libgit2`-the-library. This should make more
- // flavors of authentication possible while also still giving us all the
- // speed and portability of using `libgit2`.
if let Some(true) = config.net_config()?.git_fetch_with_cli {
- return fetch_with_cli(repo, orig_url, &refspecs, tags, config);
+ return fetch_with_cli(repo, remote_url, &refspecs, tags, config);
}
+
if config
.cli_unstable()
.gitoxide
@@ -963,10 +1044,10 @@ pub fn fetch(
)
.map_err(crate::sources::git::fetch::Error::from)
.and_then(|repo| {
- debug!("initiating fetch of {:?} from {}", refspecs, orig_url);
+ debug!("initiating fetch of {refspecs:?} from {remote_url}");
let url_for_authentication = &mut *url_for_authentication;
let remote = repo
- .remote_at(orig_url)?
+ .remote_at(remote_url)?
.with_fetch_tags(if tags {
gix::remote::fetch::Tags::All
} else {
@@ -985,10 +1066,9 @@ pub fn fetch(
let mut authenticate = connection.configured_credentials(url)?;
let connection = connection.with_credentials(
move |action: gix::protocol::credentials::helper::Action| {
- if let Some(url) = action
- .context()
- .and_then(|ctx| ctx.url.as_ref().filter(|url| *url != orig_url))
- {
+ if let Some(url) = action.context().and_then(|ctx| {
+ ctx.url.as_ref().filter(|url| *url != remote_url)
+ }) {
url_for_authentication(url.as_ref());
}
authenticate(action)
@@ -1034,9 +1114,9 @@ pub fn fetch(
}
res
} else {
- debug!("doing a fetch for {}", orig_url);
+ debug!("doing a fetch for {remote_url}");
let git_config = git2::Config::open_default()?;
- with_fetch_options(&git_config, orig_url, config, &mut |mut opts| {
+ with_fetch_options(&git_config, remote_url, config, &mut |mut opts| {
if tags {
opts.download_tags(git2::AutotagOption::All);
}
@@ -1052,10 +1132,10 @@ pub fn fetch(
// blown away the repository, then we want to return the error as-is.
let mut repo_reinitialized = false;
loop {
- debug!("initiating fetch of {:?} from {}", refspecs, orig_url);
- let res = repo
- .remote_anonymous(orig_url)?
- .fetch(&refspecs, Some(&mut opts), None);
+ debug!("initiating fetch of {refspecs:?} from {remote_url}");
+ let res =
+ repo.remote_anonymous(remote_url)?
+ .fetch(&refspecs, Some(&mut opts), None);
let err = match res {
Ok(()) => break,
Err(e) => e,
@@ -1093,6 +1173,17 @@ fn has_shallow_lock_file(err: &crate::sources::git::fetch::Error) -> bool {
)
}
+/// Attempts to use `git` CLI installed on the system to fetch a repository,
+/// when the config value [`net.git-fetch-with-cli`][1] is set.
+///
+/// Unfortunately `libgit2` is notably lacking in the realm of authentication
+/// when compared to the `git` command line. As a result, allow an escape
+/// hatch for users that would prefer to use `git`-the-CLI for fetching
+/// repositories instead of `libgit2`-the-library. This should make more
+/// flavors of authentication possible while also still giving us all the
+/// speed and portability of using `libgit2`.
+///
+/// [1]: https://doc.rust-lang.org/nightly/cargo/reference/config.html#netgit-fetch-with-cli
fn fetch_with_cli(
repo: &mut git2::Repository,
url: &str,
@@ -1137,6 +1228,8 @@ fn fetch_with_cli(
Ok(())
}
+/// Attempts to `git gc` a repository.
+///
/// Cargo has a bunch of long-lived git repositories in its global cache and
/// some, like the index, are updated very frequently. Right now each update
/// creates a new "pack file" inside the git database, and over time this can
@@ -1144,12 +1237,17 @@ fn fetch_with_cli(
///
/// One pathological use case today is where libgit2 opens hundreds of file
/// descriptors, getting us dangerously close to blowing out the OS limits of
-/// how many fds we can have open. This is detailed in #4403.
+/// how many fds we can have open. This is detailed in [#4403].
///
/// To try to combat this problem we attempt a `git gc` here. Note, though, that
/// we may not even have `git` installed on the system! As a result we
/// opportunistically try a `git gc` when the pack directory looks too big, and
/// failing that we just blow away the repository and start over.
+///
+/// In theory this shouldn't be too expensive compared to the network request
+/// we're about to issue.
+///
+/// [#4403]: https://github.com/rust-lang/cargo/issues/4403
fn maybe_gc_repo(repo: &mut git2::Repository, config: &Config) -> CargoResult<()> {
// Here we arbitrarily declare that if you have more than 100 files in your
// `pack` folder that we need to do a gc.
@@ -1236,6 +1334,8 @@ fn clean_repo_temp_files(repo: &git2::Repository) {
}
}
+/// Reinitializes a given Git repository. This is useful when a Git repoistory
+/// seems corrupted and we want to start over.
fn reinitialize(repo: &mut git2::Repository) -> CargoResult<()> {
// Here we want to drop the current repository object pointed to by `repo`,
// so we initialize temporary repository in a sub-folder, blow away the
@@ -1259,6 +1359,7 @@ fn reinitialize(repo: &mut git2::Repository) -> CargoResult<()> {
Ok(())
}
+/// Initializes a Git repository at `path`.
fn init(path: &Path, bare: bool) -> CargoResult<git2::Repository> {
let mut opts = git2::RepositoryInitOptions::new();
// Skip anything related to templates, they just call all sorts of issues as
@@ -1269,6 +1370,7 @@ fn init(path: &Path, bare: bool) -> CargoResult<git2::Repository> {
Ok(git2::Repository::init_opts(&path, &opts)?)
}
+/// The result of GitHub fast path check. See [`github_fast_path`] for more.
enum FastPathRev {
/// The local rev (determined by `reference.resolve(repo)`) is already up to
/// date with what this rev resolves to on GitHub's server.
@@ -1281,20 +1383,19 @@ enum FastPathRev {
Indeterminate,
}
+/// Attempts GitHub's special fast path for testing if we've already got an
+/// up-to-date copy of the repository.
+///
/// Updating the index is done pretty regularly so we want it to be as fast as
/// possible. For registries hosted on GitHub (like the crates.io index) there's
-/// a fast path available to use [1] to tell us that there's no updates to be
+/// a fast path available to use[^1] to tell us that there's no updates to be
/// made.
///
-/// This function will attempt to hit that fast path and verify that the `oid`
-/// is actually the current branch of the repository.
-///
-/// [1]: https://developer.github.com/v3/repos/commits/#get-the-sha-1-of-a-commit-reference
-///
/// Note that this function should never cause an actual failure because it's
-/// just a fast path. As a result all errors are ignored in this function and we
-/// just return a `bool`. Any real errors will be reported through the normal
-/// update path above.
+/// just a fast path. As a result, a caller should ignore `Err` returned from
+/// this function and move forward on the normal path.
+///
+/// [^1]: <https://developer.github.com/v3/repos/commits/#get-the-sha-1-of-a-commit-reference>
fn github_fast_path(
repo: &mut git2::Repository,
url: &str,
@@ -1406,14 +1507,17 @@ fn github_fast_path(
}
}
+/// Whether a `url` is one from GitHub.
fn is_github(url: &Url) -> bool {
url.host_str() == Some("github.com")
}
+/// Whether a `rev` looks like a commit hash (ASCII hex digits).
fn looks_like_commit_hash(rev: &str) -> bool {
rev.len() >= 7 && rev.chars().all(|ch| ch.is_ascii_hexdigit())
}
+/// Whether `rev` is a shorter hash of `oid`.
fn is_short_hash_of(rev: &str, oid: Oid) -> bool {
let long_hash = oid.to_string();
match long_hash.get(..rev.len()) {
@@ -1421,3 +1525,102 @@ fn is_short_hash_of(rev: &str, oid: Oid) -> bool {
None => false,
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::absolute_submodule_url;
+
+ #[test]
+ fn test_absolute_submodule_url() {
+ let cases = [
+ (
+ "ssh://git@gitub.com/rust-lang/cargo",
+ "git@github.com:rust-lang/cargo.git",
+ "git@github.com:rust-lang/cargo.git",
+ ),
+ (
+ "ssh://git@gitub.com/rust-lang/cargo",
+ "./",
+ "ssh://git@gitub.com/rust-lang/cargo/",
+ ),
+ (
+ "ssh://git@gitub.com/rust-lang/cargo",
+ "../",
+ "ssh://git@gitub.com/rust-lang/",
+ ),
+ (
+ "ssh://git@gitub.com/rust-lang/cargo",
+ "./foo",
+ "ssh://git@gitub.com/rust-lang/cargo/foo",
+ ),
+ (
+ "ssh://git@gitub.com/rust-lang/cargo/",
+ "./foo",
+ "ssh://git@gitub.com/rust-lang/cargo/foo",
+ ),
+ (
+ "ssh://git@gitub.com/rust-lang/cargo/",
+ "../foo",
+ "ssh://git@gitub.com/rust-lang/foo",
+ ),
+ (
+ "ssh://git@gitub.com/rust-lang/cargo",
+ "../foo",
+ "ssh://git@gitub.com/rust-lang/foo",
+ ),
+ (
+ "ssh://git@gitub.com/rust-lang/cargo",
+ "../foo/bar/../baz",
+ "ssh://git@gitub.com/rust-lang/foo/baz",
+ ),
+ (
+ "git@github.com:rust-lang/cargo.git",
+ "ssh://git@gitub.com/rust-lang/cargo",
+ "ssh://git@gitub.com/rust-lang/cargo",
+ ),
+ (
+ "git@github.com:rust-lang/cargo.git",
+ "./",
+ "git@github.com:rust-lang/cargo.git/./",
+ ),
+ (
+ "git@github.com:rust-lang/cargo.git",
+ "../",
+ "git@github.com:rust-lang/cargo.git/../",
+ ),
+ (
+ "git@github.com:rust-lang/cargo.git",
+ "./foo",
+ "git@github.com:rust-lang/cargo.git/./foo",
+ ),
+ (
+ "git@github.com:rust-lang/cargo.git/",
+ "./foo",
+ "git@github.com:rust-lang/cargo.git/./foo",
+ ),
+ (
+ "git@github.com:rust-lang/cargo.git",
+ "../foo",
+ "git@github.com:rust-lang/cargo.git/../foo",
+ ),
+ (
+ "git@github.com:rust-lang/cargo.git/",
+ "../foo",
+ "git@github.com:rust-lang/cargo.git/../foo",
+ ),
+ (
+ "git@github.com:rust-lang/cargo.git",
+ "../foo/bar/../baz",
+ "git@github.com:rust-lang/cargo.git/../foo/bar/../baz",
+ ),
+ ];
+
+ for (base_url, submodule_url, expected) in cases {
+ let url = absolute_submodule_url(base_url, submodule_url).unwrap();
+ assert_eq!(
+ expected, url,
+ "base `{base_url}`; submodule `{submodule_url}`"
+ );
+ }
+ }
+}
diff --git a/src/tools/cargo/src/cargo/sources/path.rs b/src/tools/cargo/src/cargo/sources/path.rs
index 2f147b19e..bb40ec9b1 100644
--- a/src/tools/cargo/src/cargo/sources/path.rs
+++ b/src/tools/cargo/src/cargo/sources/path.rs
@@ -95,7 +95,7 @@ impl<'cfg> PathSource<'cfg> {
}
/// Returns the packages discovered by this source. It may walk the
- /// the filesystem if package informations haven't yet updated.
+ /// filesystem if package informations haven't yet updated.
pub fn read_packages(&self) -> CargoResult<Vec<Package>> {
if self.updated {
Ok(self.packages.clone())
diff --git a/src/tools/cargo/src/cargo/sources/registry/download.rs b/src/tools/cargo/src/cargo/sources/registry/download.rs
index 723c55ffd..a85d87177 100644
--- a/src/tools/cargo/src/cargo/sources/registry/download.rs
+++ b/src/tools/cargo/src/cargo/sources/registry/download.rs
@@ -1,13 +1,15 @@
+//! Shared download logic between [`HttpRegistry`] and [`RemoteRegistry`].
+//!
+//! [`HttpRegistry`]: super::http_remote::HttpRegistry
+//! [`RemoteRegistry`]: super::remote::RemoteRegistry
+
use anyhow::Context;
+use cargo_util::registry::make_dep_path;
use cargo_util::Sha256;
use crate::core::PackageId;
-use crate::sources::registry::make_dep_prefix;
use crate::sources::registry::MaybeLock;
-use crate::sources::registry::{
- RegistryConfig, CHECKSUM_TEMPLATE, CRATE_TEMPLATE, LOWER_PREFIX_TEMPLATE, PREFIX_TEMPLATE,
- VERSION_TEMPLATE,
-};
+use crate::sources::registry::RegistryConfig;
use crate::util::auth;
use crate::util::errors::CargoResult;
use crate::util::{Config, Filesystem};
@@ -17,10 +19,16 @@ use std::io::prelude::*;
use std::io::SeekFrom;
use std::str;
-pub(super) fn filename(pkg: PackageId) -> String {
- format!("{}-{}.crate", pkg.name(), pkg.version())
-}
+const CRATE_TEMPLATE: &str = "{crate}";
+const VERSION_TEMPLATE: &str = "{version}";
+const PREFIX_TEMPLATE: &str = "{prefix}";
+const LOWER_PREFIX_TEMPLATE: &str = "{lowerprefix}";
+const CHECKSUM_TEMPLATE: &str = "{sha256-checksum}";
+/// Checks if `pkg` is downloaded and ready under the directory at `cache_path`.
+/// If not, returns a URL to download it from.
+///
+/// This is primarily called by [`RegistryData::download`](super::RegistryData::download).
pub(super) fn download(
cache_path: &Filesystem,
config: &Config,
@@ -28,8 +36,7 @@ pub(super) fn download(
checksum: &str,
registry_config: RegistryConfig,
) -> CargoResult<MaybeLock> {
- let filename = filename(pkg);
- let path = cache_path.join(&filename);
+ let path = cache_path.join(&pkg.tarball_name());
let path = config.assert_package_cache_locked(&path);
// Attempt to open a read-only copy first to avoid an exclusive write
@@ -61,7 +68,7 @@ pub(super) fn download(
)
.unwrap();
} else {
- let prefix = make_dep_prefix(&*pkg.name());
+ let prefix = make_dep_path(&pkg.name(), true);
url = url
.replace(CRATE_TEMPLATE, &*pkg.name())
.replace(VERSION_TEMPLATE, &pkg.version().to_string())
@@ -83,6 +90,10 @@ pub(super) fn download(
})
}
+/// Verifies the integrity of `data` with `checksum` and persists it under the
+/// directory at `cache_path`.
+///
+/// This is primarily called by [`RegistryData::finish_download`](super::RegistryData::finish_download).
pub(super) fn finish_download(
cache_path: &Filesystem,
config: &Config,
@@ -96,9 +107,8 @@ pub(super) fn finish_download(
anyhow::bail!("failed to verify the checksum of `{}`", pkg)
}
- let filename = filename(pkg);
cache_path.create_dir()?;
- let path = cache_path.join(&filename);
+ let path = cache_path.join(&pkg.tarball_name());
let path = config.assert_package_cache_locked(&path);
let mut dst = OpenOptions::new()
.create(true)
@@ -116,12 +126,16 @@ pub(super) fn finish_download(
Ok(dst)
}
+/// Checks if a tarball of `pkg` has been already downloaded under the
+/// directory at `cache_path`.
+///
+/// This is primarily called by [`RegistryData::is_crate_downloaded`](super::RegistryData::is_crate_downloaded).
pub(super) fn is_crate_downloaded(
cache_path: &Filesystem,
config: &Config,
pkg: PackageId,
) -> bool {
- let path = cache_path.join(filename(pkg));
+ let path = cache_path.join(pkg.tarball_name());
let path = config.assert_package_cache_locked(&path);
if let Ok(meta) = fs::metadata(path) {
return meta.len() > 0;
diff --git a/src/tools/cargo/src/cargo/sources/registry/http_remote.rs b/src/tools/cargo/src/cargo/sources/registry/http_remote.rs
index 7e1f2a587..c69ef8f9b 100644
--- a/src/tools/cargo/src/cargo/sources/registry/http_remote.rs
+++ b/src/tools/cargo/src/cargo/sources/registry/http_remote.rs
@@ -1,21 +1,19 @@
-//! Access to a HTTP-based crate registry.
-//!
-//! See [`HttpRegistry`] for details.
+//! Access to a HTTP-based crate registry. See [`HttpRegistry`] for details.
use crate::core::{PackageId, SourceId};
-use crate::ops::{self};
use crate::sources::registry::download;
use crate::sources::registry::MaybeLock;
use crate::sources::registry::{LoadResponse, RegistryConfig, RegistryData};
use crate::util::errors::{CargoResult, HttpNotSuccessful, DEBUG_HEADERS};
+use crate::util::network::http::http_handle;
use crate::util::network::retry::{Retry, RetryResult};
use crate::util::network::sleep::SleepTracker;
use crate::util::{auth, Config, Filesystem, IntoUrl, Progress, ProgressStyle};
use anyhow::Context;
use cargo_util::paths;
-use curl::easy::{Easy, HttpVersion, List};
+use curl::easy::{Easy, List};
use curl::multi::{EasyHandle, Multi};
-use log::{debug, trace, warn};
+use log::{debug, trace};
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::fs::{self, File};
@@ -52,8 +50,15 @@ const UNKNOWN: &'static str = "Unknown";
///
/// [RFC 2789]: https://github.com/rust-lang/rfcs/pull/2789
pub struct HttpRegistry<'cfg> {
+ /// Path to the registry index (`$CARGO_HOME/registry/index/$REG-HASH`).
+ ///
+ /// To be fair, `HttpRegistry` doesn't store the registry index it
+ /// downloads on the file system, but other cached data like registry
+ /// configuration could be stored here.
index_path: Filesystem,
+ /// Path to the cache of `.crate` files (`$CARGO_HOME/registry/cache/$REG-HASH`).
cache_path: Filesystem,
+ /// The unique identifier of this registry source.
source_id: SourceId,
config: &'cfg Config,
@@ -95,20 +100,20 @@ pub struct HttpRegistry<'cfg> {
quiet: bool,
}
-/// Helper for downloading crates.
+/// State for currently pending index file downloads.
struct Downloads<'cfg> {
/// When a download is started, it is added to this map. The key is a
- /// "token" (see `Download::token`). It is removed once the download is
+ /// "token" (see [`Download::token`]). It is removed once the download is
/// finished.
pending: HashMap<usize, (Download<'cfg>, EasyHandle)>,
/// Set of paths currently being downloaded.
- /// This should stay in sync with `pending`.
+ /// This should stay in sync with the `pending` field.
pending_paths: HashSet<PathBuf>,
/// Downloads that have failed and are waiting to retry again later.
sleeping: SleepTracker<(Download<'cfg>, Easy)>,
/// The final result of each download.
results: HashMap<PathBuf, CargoResult<CompletedDownload>>,
- /// The next ID to use for creating a token (see `Download::token`).
+ /// The next ID to use for creating a token (see [`Download::token`]).
next: usize,
/// Progress bar.
progress: RefCell<Option<Progress<'cfg>>>,
@@ -119,9 +124,10 @@ struct Downloads<'cfg> {
blocking_calls: usize,
}
+/// Represents a single index file download, including its progress and retry.
struct Download<'cfg> {
- /// The token for this download, used as the key of the `Downloads::pending` map
- /// and stored in `EasyHandle` as well.
+ /// The token for this download, used as the key of the
+ /// [`Downloads::pending`] map and stored in [`EasyHandle`] as well.
token: usize,
/// The path of the package that we're downloading.
@@ -137,14 +143,17 @@ struct Download<'cfg> {
retry: Retry<'cfg>,
}
+/// HTTPS headers [`HttpRegistry`] cares about.
#[derive(Default)]
struct Headers {
last_modified: Option<String>,
etag: Option<String>,
www_authenticate: Vec<String>,
+ /// We don't care about these headers. Put them here for debugging purpose.
others: Vec<String>,
}
+/// HTTP status code [`HttpRegistry`] cares about.
enum StatusCode {
Success,
NotModified,
@@ -152,6 +161,10 @@ enum StatusCode {
Unauthorized,
}
+/// Represents a complete [`Download`] from an HTTP request.
+///
+/// Usually it is constructed in [`HttpRegistry::handle_completed_downloads`],
+/// and then returns to the caller of [`HttpRegistry::load()`].
struct CompletedDownload {
response_code: StatusCode,
data: Vec<u8>,
@@ -159,6 +172,10 @@ struct CompletedDownload {
}
impl<'cfg> HttpRegistry<'cfg> {
+ /// Creates a HTTP-rebased remote registry for `source_id`.
+ ///
+ /// * `name` --- Name of a path segment where `.crate` tarballs and the
+ /// registry index are stored. Expect to be unique.
pub fn new(
source_id: SourceId,
config: &'cfg Config,
@@ -208,6 +225,7 @@ impl<'cfg> HttpRegistry<'cfg> {
})
}
+ /// Splits HTTP `HEADER: VALUE` to a tuple.
fn handle_http_header(buf: &[u8]) -> Option<(&str, &str)> {
if buf.is_empty() {
return None;
@@ -222,6 +240,9 @@ impl<'cfg> HttpRegistry<'cfg> {
Some((tag, value))
}
+ /// Setup the necessary works before the first fetch gets started.
+ ///
+ /// This is a no-op if called more than one time.
fn start_fetch(&mut self) -> CargoResult<()> {
if self.fetch_started {
// We only need to run the setup code once.
@@ -249,6 +270,8 @@ impl<'cfg> HttpRegistry<'cfg> {
Ok(())
}
+ /// Checks the results inside the [`HttpRegistry::multi`] handle, and
+ /// updates relevant state in [`HttpRegistry::downloads`] accordingly.
fn handle_completed_downloads(&mut self) -> CargoResult<()> {
assert_eq!(
self.downloads.pending.len(),
@@ -322,11 +345,15 @@ impl<'cfg> HttpRegistry<'cfg> {
Ok(())
}
+ /// Constructs the full URL to download a index file.
fn full_url(&self, path: &Path) -> String {
// self.url always ends with a slash.
format!("{}{}", self.url, path.display())
}
+ /// Check if an index file of `path` is up-to-date.
+ ///
+ /// The `path` argument is the same as in [`RegistryData::load`].
fn is_fresh(&self, path: &Path) -> bool {
if !self.requested_update {
trace!(
@@ -356,7 +383,7 @@ impl<'cfg> HttpRegistry<'cfg> {
}
let config_json_path = self
.assert_index_locked(&self.index_path)
- .join("config.json");
+ .join(RegistryConfig::NAME);
match fs::read(&config_json_path) {
Ok(raw_data) => match serde_json::from_slice(&raw_data) {
Ok(json) => {
@@ -373,16 +400,16 @@ impl<'cfg> HttpRegistry<'cfg> {
Ok(self.registry_config.as_ref())
}
- /// Get the registry configuration.
+ /// Get the registry configuration from either cache or remote.
fn config(&mut self) -> Poll<CargoResult<&RegistryConfig>> {
debug!("loading config");
let index_path = self.assert_index_locked(&self.index_path);
- let config_json_path = index_path.join("config.json");
- if self.is_fresh(Path::new("config.json")) && self.config_cached()?.is_some() {
+ let config_json_path = index_path.join(RegistryConfig::NAME);
+ if self.is_fresh(Path::new(RegistryConfig::NAME)) && self.config_cached()?.is_some() {
return Poll::Ready(Ok(self.registry_config.as_ref().unwrap()));
}
- match ready!(self.load(Path::new(""), Path::new("config.json"), None)?) {
+ match ready!(self.load(Path::new(""), Path::new(RegistryConfig::NAME), None)?) {
LoadResponse::Data {
raw_data,
index_version: _,
@@ -405,6 +432,7 @@ impl<'cfg> HttpRegistry<'cfg> {
}
}
+ /// Moves failed [`Download`]s that are ready to retry to the pending queue.
fn add_sleepers(&mut self) -> CargoResult<()> {
for (dl, handle) in self.downloads.sleeping.to_retry() {
let mut handle = self.multi.add(handle)?;
@@ -515,7 +543,7 @@ impl<'cfg> RegistryData for HttpRegistry<'cfg> {
}
StatusCode::Unauthorized
if !self.auth_required
- && path == Path::new("config.json")
+ && path == Path::new(RegistryConfig::NAME)
&& self.config.cli_unstable().registry_auth =>
{
debug!("re-attempting request for config.json with authorization included.");
@@ -565,7 +593,7 @@ impl<'cfg> RegistryData for HttpRegistry<'cfg> {
}
}
- if path != Path::new("config.json") {
+ if path != Path::new(RegistryConfig::NAME) {
self.auth_required = ready!(self.config()?).auth_required;
} else if !self.auth_required {
// Check if there's a cached config that says auth is required.
@@ -582,7 +610,7 @@ impl<'cfg> RegistryData for HttpRegistry<'cfg> {
// Looks like we're going to have to do a network request.
self.start_fetch()?;
- let mut handle = ops::http_handle(self.config)?;
+ let mut handle = http_handle(self.config)?;
let full_url = self.full_url(path);
debug!("fetch {}", full_url);
handle.get(true)?;
@@ -590,20 +618,7 @@ impl<'cfg> RegistryData for HttpRegistry<'cfg> {
handle.follow_location(true)?;
// Enable HTTP/2 if possible.
- if self.multiplexing {
- crate::try_old_curl!(handle.http_version(HttpVersion::V2), "HTTP2");
- } else {
- handle.http_version(HttpVersion::V11)?;
- }
-
- // This is an option to `libcurl` which indicates that if there's a
- // bunch of parallel requests to the same host they all wait until the
- // pipelining status of the host is known. This means that we won't
- // initiate dozens of connections to crates.io, but rather only one.
- // Once the main one is opened we realized that pipelining is possible
- // and multiplexing is possible with static.crates.io. All in all this
- // reduces the number of connections done to a more manageable state.
- crate::try_old_curl!(handle.pipewait(true), "pipewait");
+ crate::try_old_curl_http2_pipewait!(self.multiplexing, handle);
let mut headers = List::new();
// Include a header to identify the protocol. This allows the server to
@@ -790,6 +805,7 @@ impl<'cfg> RegistryData for HttpRegistry<'cfg> {
}
impl<'cfg> Downloads<'cfg> {
+ /// Updates the state of the progress bar for downloads.
fn tick(&self) -> CargoResult<()> {
let mut progress = self.progress.borrow_mut();
let Some(progress) = progress.as_mut() else { return Ok(()); };
diff --git a/src/tools/cargo/src/cargo/sources/registry/index.rs b/src/tools/cargo/src/cargo/sources/registry/index.rs
index d857a053e..6d565da8f 100644
--- a/src/tools/cargo/src/cargo/sources/registry/index.rs
+++ b/src/tools/cargo/src/cargo/sources/registry/index.rs
@@ -1,11 +1,26 @@
-//! Management of the index of a registry source
+//! Management of the index of a registry source.
//!
//! This module contains management of the index and various operations, such as
//! actually parsing the index, looking for crates, etc. This is intended to be
-//! abstract over remote indices (downloaded via git) and local registry indices
-//! (which are all just present on the filesystem).
+//! abstract over remote indices (downloaded via Git or HTTP) and local registry
+//! indices (which are all just present on the filesystem).
//!
-//! ## Index Performance
+//! ## How the index works
+//!
+//! Here is a simple flow when loading a [`Summary`] (metadata) from the index:
+//!
+//! 1. A query is fired via [`RegistryIndex::query_inner`].
+//! 2. Tries loading all summaries via [`RegistryIndex::load_summaries`], and
+//! under the hood calling [`Summaries::parse`] to parse an index file.
+//! 1. If an on-disk index cache is present, loads it via
+//! [`Summaries::parse_cache`].
+//! 2. Otherwise goes to the slower path [`RegistryData::load`] to get the
+//! specific index file.
+//! 3. A [`Summary`] is now ready in callback `f` in [`RegistryIndex::query_inner`].
+//!
+//! This is just an overview. To know the rationale behind, continue reading.
+//!
+//! ## A layer of on-disk index cache for performance
//!
//! One important aspect of the index is that we want to optimize the "happy
//! path" as much as possible. Whenever you type `cargo build` Cargo will
@@ -20,19 +35,20 @@
//! don't need them. Most secondary optimizations are centered around removing
//! allocations and such, but avoiding parsing JSON is the #1 optimization.
//!
-//! When we get queries from the resolver we're given a `Dependency`. This
+//! When we get queries from the resolver we're given a [`Dependency`]. This
//! dependency in turn has a version requirement, and with lock files that
//! already exist these version requirements are exact version requirements
//! `=a.b.c`. This means that we in theory only need to parse one line of JSON
//! per query in the registry, the one that matches version `a.b.c`.
//!
//! The crates.io index, however, is not amenable to this form of query. Instead
-//! the crates.io index simply is a file where each line is a JSON blob. To
-//! learn about the versions in each JSON blob we would need to parse the JSON,
-//! defeating the purpose of trying to parse as little as possible.
+//! the crates.io index simply is a file where each line is a JSON blob, aka
+//! [`IndexPackage`]. To learn about the versions in each JSON blob we would
+//! need to parse the JSON via [`IndexSummary::parse`], defeating the purpose
+//! of trying to parse as little as possible.
//!
//! > Note that as a small aside even *loading* the JSON from the registry is
-//! > actually pretty slow. For crates.io and remote registries we don't
+//! > actually pretty slow. For crates.io and [`RemoteRegistry`] we don't
//! > actually check out the git index on disk because that takes quite some
//! > time and is quite large. Instead we use `libgit2` to read the JSON from
//! > the raw git objects. This in turn can be slow (aka show up high in
@@ -43,14 +59,14 @@
//! (first time being for an entire computer) Cargo will load the contents
//! (slowly via libgit2) from the registry. It will then (slowly) parse every
//! single line to learn about its versions. Afterwards, however, Cargo will
-//! emit a new file (a cache) which is amenable for speedily parsing in future
-//! invocations.
+//! emit a new file (a cache, representing as [`SummariesCache`]) which is
+//! amenable for speedily parsing in future invocations.
//!
//! This cache file is currently organized by basically having the semver
-//! version extracted from each JSON blob. That way Cargo can quickly and easily
-//! parse all versions contained and which JSON blob they're associated with.
-//! The JSON blob then doesn't actually need to get parsed unless the version is
-//! parsed.
+//! version extracted from each JSON blob. That way Cargo can quickly and
+//! easily parse all versions contained and which JSON blob they're associated
+//! with. The JSON blob then doesn't actually need to get parsed unless the
+//! version is parsed.
//!
//! Altogether the initial measurements of this shows a massive improvement for
//! Cargo null build performance. It's expected that the improvements earned
@@ -65,15 +81,24 @@
//! Note that this is just a high-level overview, there's of course lots of
//! details like invalidating caches and whatnot which are handled below, but
//! hopefully those are more obvious inline in the code itself.
+//!
+//! [`RemoteRegistry`]: super::remote::RemoteRegistry
+//! [`Dependency`]: crate::core::Dependency
+use crate::core::dependency::DepKind;
+use crate::core::Dependency;
use crate::core::{PackageId, SourceId, Summary};
-use crate::sources::registry::{LoadResponse, RegistryData, RegistryPackage, INDEX_V_MAX};
+use crate::sources::registry::{LoadResponse, RegistryData};
use crate::util::interning::InternedString;
+use crate::util::IntoUrl;
use crate::util::{internal, CargoResult, Config, Filesystem, OptVersionReq, ToSemver};
use anyhow::bail;
use cargo_util::{paths, registry::make_dep_path};
use log::{debug, info};
use semver::Version;
+use serde::Deserialize;
+use std::borrow::Cow;
+use std::collections::BTreeMap;
use std::collections::{HashMap, HashSet};
use std::fs;
use std::io::ErrorKind;
@@ -81,19 +106,33 @@ use std::path::Path;
use std::str;
use std::task::{ready, Poll};
+/// The current version of [`SummariesCache`].
+const CURRENT_CACHE_VERSION: u8 = 3;
+
+/// The maximum schema version of the `v` field in the index this version of
+/// cargo understands. See [`IndexPackage::v`] for the detail.
+const INDEX_V_MAX: u32 = 2;
+
/// Manager for handling the on-disk index.
///
-/// Note that local and remote registries store the index differently. Local
-/// is a simple on-disk tree of files of the raw index. Remote registries are
-/// stored as a raw git repository. The different means of access are handled
-/// via the [`RegistryData`] trait abstraction.
+/// Different kinds of registries store the index differently:
///
+/// * [`LocalRegistry`]` is a simple on-disk tree of files of the raw index.
+/// * [`RemoteRegistry`] is stored as a raw git repository.
+/// * [`HttpRegistry`] fills the on-disk index cache directly without keeping
+/// any raw index.
+///
+/// These means of access are handled via the [`RegistryData`] trait abstraction.
/// This transparently handles caching of the index in a more efficient format.
+///
+/// [`LocalRegistry`]: super::local::LocalRegistry
+/// [`RemoteRegistry`]: super::remote::RemoteRegistry
+/// [`HttpRegistry`]: super::http_remote::HttpRegistry
pub struct RegistryIndex<'cfg> {
source_id: SourceId,
/// Root directory of the index for the registry.
path: Filesystem,
- /// Cache of summary data.
+ /// In-memory cache of summary data.
///
/// This is keyed off the package name. The [`Summaries`] value handles
/// loading the summary data. It keeps an optimized on-disk representation
@@ -110,14 +149,16 @@ pub struct RegistryIndex<'cfg> {
///
/// A list of summaries are loaded from disk via one of two methods:
///
-/// 1. Primarily Cargo will parse the corresponding file for a crate in the
-/// upstream crates.io registry. That's just a JSON blob per line which we
-/// can parse, extract the version, and then store here.
+/// 1. From raw registry index --- Primarily Cargo will parse the corresponding
+/// file for a crate in the upstream crates.io registry. That's just a JSON
+/// blob per line which we can parse, extract the version, and then store here.
+/// See [`IndexPackage`] and [`IndexSummary::parse`].
///
-/// 2. Alternatively, if Cargo has previously run, we'll have a cached index of
-/// dependencies for the upstream index. This is a file that Cargo maintains
-/// lazily on the local filesystem and is much faster to parse since it
-/// doesn't involve parsing all of the JSON.
+/// 2. From on-disk index cache --- If Cargo has previously run, we'll have a
+/// cached index of dependencies for the upstream index. This is a file that
+/// Cargo maintains lazily on the local filesystem and is much faster to
+/// parse since it doesn't involve parsing all of the JSON.
+/// See [`SummariesCache`].
///
/// The outward-facing interface of this doesn't matter too much where it's
/// loaded from, but it's important when reading the implementation to note that
@@ -134,37 +175,191 @@ struct Summaries {
versions: HashMap<Version, MaybeIndexSummary>,
}
-/// A lazily parsed `IndexSummary`.
+/// A lazily parsed [`IndexSummary`].
enum MaybeIndexSummary {
/// A summary which has not been parsed, The `start` and `end` are pointers
- /// into `Summaries::raw_data` which this is an entry of.
+ /// into [`Summaries::raw_data`] which this is an entry of.
Unparsed { start: usize, end: usize },
/// An actually parsed summary.
Parsed(IndexSummary),
}
-/// A parsed representation of a summary from the index.
+/// A parsed representation of a summary from the index. This is usually parsed
+/// from a line from a raw index file, or a JSON blob from on-disk index cache.
///
-/// In addition to a full `Summary` we have information on whether it is `yanked`.
+/// In addition to a full [`Summary`], we have information on whether it is `yanked`.
pub struct IndexSummary {
pub summary: Summary,
pub yanked: bool,
- /// Schema version, see [`RegistryPackage`].
+ /// Schema version, see [`IndexPackage::v`].
v: u32,
}
/// A representation of the cache on disk that Cargo maintains of summaries.
+///
/// Cargo will initially parse all summaries in the registry and will then
/// serialize that into this form and place it in a new location on disk,
/// ensuring that access in the future is much speedier.
+///
+/// For serialization and deserialization of this on-disk index cache of
+/// summaries, see [`SummariesCache::serialize`] and [`SummariesCache::parse`].
+///
+/// # The format of the index cache
+///
+/// The idea of this format is that it's a very easy file for Cargo to parse in
+/// future invocations. The read from disk should be fast and then afterwards
+/// all we need to know is what versions correspond to which JSON blob.
+///
+/// Currently the format looks like:
+///
+/// ```text
+/// +---------------+----------------------+--------------------+---+
+/// | cache version | index schema version | index file version | 0 |
+/// +---------------+----------------------+--------------------+---+
+/// ```
+///
+/// followed by one or more (version + JSON blob) pairs...
+///
+/// ```text
+/// +----------------+---+-----------+---+
+/// | semver version | 0 | JSON blob | 0 | ...
+/// +----------------+---+-----------+---+
+/// ```
+///
+/// Each field represents:
+///
+/// * _cache version_ --- Intended to ensure that there's some level of
+/// future compatibility against changes to this cache format so if different
+/// versions of Cargo share the same cache they don't get too confused.
+/// * _index schema version_ --- The schema version of the raw index file.
+/// See [`IndexPackage::v`] for the detail.
+/// * _index file version_ --- Tracks when a cache needs to be regenerated.
+/// A cache regeneration is required whenever the index file itself updates.
+/// * _semver version_ --- The version for each JSON blob. Extracted from the
+/// blob for fast queries without parsing the entire blob.
+/// * _JSON blob_ --- The actual metadata for each version of the package. It
+/// has the same representation as [`IndexPackage`].
+///
+/// # Changes between each cache version
+///
+/// * `1`: The original version.
+/// * `2`: Added the "index schema version" field so that if the index schema
+/// changes, different versions of cargo won't get confused reading each
+/// other's caches.
+/// * `3`: Bumped the version to work around an issue where multiple versions of
+/// a package were published that differ only by semver metadata. For
+/// example, openssl-src 110.0.0 and 110.0.0+1.1.0f. Previously, the cache
+/// would be incorrectly populated with two entries, both 110.0.0. After
+/// this, the metadata will be correctly included. This isn't really a format
+/// change, just a version bump to clear the incorrect cache entries. Note:
+/// the index shouldn't allow these, but unfortunately crates.io doesn't
+/// check it.
+///
+/// See [`CURRENT_CACHE_VERSION`] for the current cache version.
#[derive(Default)]
struct SummariesCache<'a> {
+ /// JSON blobs of the summaries. Each JSON blob has a [`Version`] beside,
+ /// so that Cargo can query a version without full JSON parsing.
versions: Vec<(Version, &'a [u8])>,
+ /// For cache invalidation, we tracks the index file version to determine
+ /// when to regenerate the cache itself.
index_version: &'a str,
}
+/// A single line in the index representing a single version of a package.
+#[derive(Deserialize)]
+pub struct IndexPackage<'a> {
+ /// Name of the pacakge.
+ name: InternedString,
+ /// The version of this dependency.
+ vers: Version,
+ /// All kinds of direct dependencies of the package, including dev and
+ /// build dependencies.
+ #[serde(borrow)]
+ deps: Vec<RegistryDependency<'a>>,
+ /// Set of features defined for the package, i.e., `[features]` table.
+ features: BTreeMap<InternedString, Vec<InternedString>>,
+ /// This field contains features with new, extended syntax. Specifically,
+ /// namespaced features (`dep:`) and weak dependencies (`pkg?/feat`).
+ ///
+ /// This is separated from `features` because versions older than 1.19
+ /// will fail to load due to not being able to parse the new syntax, even
+ /// with a `Cargo.lock` file.
+ features2: Option<BTreeMap<InternedString, Vec<InternedString>>>,
+ /// Checksum for verifying the integrity of the corresponding downloaded package.
+ cksum: String,
+ /// If `true`, Cargo will skip this version when resolving.
+ ///
+ /// This was added in 2014. Everything in the crates.io index has this set
+ /// now, so this probably doesn't need to be an option anymore.
+ yanked: Option<bool>,
+ /// Native library name this package links to.
+ ///
+ /// 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
+ /// versions are ignored.
+ ///
+ /// Version `2` schema adds the `features2` field.
+ ///
+ /// This provides a method to safely introduce changes to index entries
+ /// and allow older versions of cargo to ignore newer entries it doesn't
+ /// understand. This is honored as of 1.51, so unfortunately older
+ /// versions will ignore it, and potentially misinterpret version 2 and
+ /// newer entries.
+ ///
+ /// The intent is that versions older than 1.51 will work with a
+ /// pre-existing `Cargo.lock`, but they may not correctly process `cargo
+ /// update` or build a lock from scratch. In that case, cargo may
+ /// incorrectly select a new package that uses a new index schema. A
+ /// workaround is to downgrade any packages that are incompatible with the
+ /// `--precise` flag of `cargo update`.
+ v: Option<u32>,
+}
+
+/// A dependency as encoded in the [`IndexPackage`] index JSON.
+#[derive(Deserialize)]
+struct RegistryDependency<'a> {
+ /// Name of the dependency. If the dependency is renamed, the original
+ /// would be stored in [`RegistryDependency::package`].
+ name: InternedString,
+ /// The SemVer requirement for this dependency.
+ #[serde(borrow)]
+ req: Cow<'a, str>,
+ /// Set of features enabled for this dependency.
+ features: Vec<InternedString>,
+ /// Whether or not this is an optional dependency.
+ optional: bool,
+ /// Whether or not default features are enabled.
+ default_features: bool,
+ /// The target platform for this dependency.
+ target: Option<Cow<'a, str>>,
+ /// The dependency kind. "dev", "build", and "normal".
+ kind: Option<Cow<'a, str>>,
+ // The URL of the index of the registry where this dependency is from.
+ // `None` if it is from the same index.
+ registry: Option<Cow<'a, str>>,
+ /// The original name if the dependency is renamed.
+ package: Option<InternedString>,
+ /// Whether or not this is a public dependency. Unstable. See [RFC 1977].
+ ///
+ /// [RFC 1977]: https://rust-lang.github.io/rfcs/1977-public-private-dependencies.html
+ public: Option<bool>,
+}
+
impl<'cfg> RegistryIndex<'cfg> {
+ /// Creates an empty registry index at `path`.
pub fn new(
source_id: SourceId,
path: &Filesystem,
@@ -178,7 +373,9 @@ impl<'cfg> RegistryIndex<'cfg> {
}
}
- /// Returns the hash listed for a specified `PackageId`.
+ /// Returns the hash listed for a specified `PackageId`. Primarily for
+ /// checking the integrity of a downloaded package matching the checksum in
+ /// the index file, aka [`IndexSummary`].
pub fn hash(&mut self, pkg: PackageId, load: &mut dyn RegistryData) -> Poll<CargoResult<&str>> {
let req = OptVersionReq::exact(pkg.version());
let summary = self.summaries(&pkg.name(), &req, load)?;
@@ -191,10 +388,14 @@ impl<'cfg> RegistryIndex<'cfg> {
}
/// Load a list of summaries for `name` package in this registry which
- /// match `req`
+ /// match `req`.
+ ///
+ /// This function will semantically
+ ///
+ /// 1. parse the index file (either raw or cache),
+ /// 2. match all versions,
+ /// 3. and then return an iterator over all summaries which matched.
///
- /// This function will semantically parse the on-disk index, match all
- /// versions, and then return an iterator over all summaries which matched.
/// Internally there's quite a few layer of caching to amortize this cost
/// though since this method is called quite a lot on null builds in Cargo.
pub fn summaries<'a, 'b>(
@@ -207,12 +408,8 @@ impl<'cfg> RegistryIndex<'cfg> {
'a: 'b,
{
let source_id = self.source_id;
- let config = self.config;
- // First up actually parse what summaries we have available. If Cargo
- // has run previously this will parse a Cargo-specific cache file rather
- // than the registry itself. In effect this is intended to be a quite
- // cheap operation.
+ // First up parse what summaries we have available.
let name = InternedString::new(name);
let summaries = ready!(self.load_summaries(name, load)?);
@@ -227,15 +424,13 @@ impl<'cfg> RegistryIndex<'cfg> {
.versions
.iter_mut()
.filter_map(move |(k, v)| if req.matches(k) { Some(v) } else { None })
- .filter_map(
- move |maybe| match maybe.parse(config, raw_data, source_id) {
- Ok(summary) => Some(summary),
- Err(e) => {
- info!("failed to parse `{}` registry package: {}", name, e);
- None
- }
- },
- )
+ .filter_map(move |maybe| match maybe.parse(raw_data, source_id) {
+ Ok(summary) => Some(summary),
+ Err(e) => {
+ info!("failed to parse `{}` registry package: {}", name, e);
+ None
+ }
+ })
.filter(move |is| {
if is.v > INDEX_V_MAX {
debug!(
@@ -251,13 +446,28 @@ impl<'cfg> RegistryIndex<'cfg> {
})))
}
+ /// Actually parses what summaries we have available.
+ ///
+ /// If Cargo has run previously, this tries in this order:
+ ///
+ /// 1. Returns from in-memory cache, aka [`RegistryIndex::summaries_cache`].
+ /// 2. If missing, hands over to [`Summaries::parse`] to parse an index file.
+ ///
+ /// The actual kind index file being parsed depends on which kind of
+ /// [`RegistryData`] the `load` argument is given. For example, a
+ /// Git-based [`RemoteRegistry`] will first try a on-disk index cache
+ /// file, and then try parsing registry raw index fomr Git repository.
+ ///
+ /// In effect, this is intended to be a quite cheap operation.
+ ///
+ /// [`RemoteRegistry`]: super::remote::RemoteRegistry
fn load_summaries(
&mut self,
name: InternedString,
load: &mut dyn RegistryData,
) -> Poll<CargoResult<&mut Summaries>> {
// If we've previously loaded what versions are present for `name`, just
- // return that since our cache should still be valid.
+ // return that since our in-memory cache should still be valid.
if self.summaries_cache.contains_key(&name) {
return Poll::Ready(Ok(self.summaries_cache.get_mut(&name).unwrap()));
}
@@ -271,12 +481,7 @@ impl<'cfg> RegistryIndex<'cfg> {
// See module comment in `registry/mod.rs` for why this is structured
// the way it is.
- let fs_name = name
- .chars()
- .flat_map(|c| c.to_lowercase())
- .collect::<String>();
-
- let path = make_dep_path(&fs_name, false);
+ let path = make_dep_path(&name.to_lowercase(), false);
let summaries = ready!(Summaries::parse(
root,
&cache_root,
@@ -295,6 +500,9 @@ impl<'cfg> RegistryIndex<'cfg> {
self.summaries_cache.clear();
}
+ /// Attempts to find the packages that match a `name` and a version `req`.
+ ///
+ /// This is primarily used by [`Source::query`](super::Source).
pub fn query_inner(
&mut self,
name: &str,
@@ -324,6 +532,10 @@ impl<'cfg> RegistryIndex<'cfg> {
.map_ok(|_| ())
}
+ /// Inner implementation of [`Self::query_inner`]. Returns the number of
+ /// summaries we've got.
+ ///
+ /// The `online` controls whether Cargo can access the network when needed.
fn query_inner_with_online(
&mut self,
name: &str,
@@ -404,6 +616,7 @@ impl<'cfg> RegistryIndex<'cfg> {
Poll::Ready(Ok(count))
}
+ /// Looks into the summaries to check if a package has been yanked.
pub fn is_yanked(
&mut self,
pkg: PackageId,
@@ -418,23 +631,26 @@ impl<'cfg> RegistryIndex<'cfg> {
}
impl Summaries {
- /// Parse out a `Summaries` instances from on-disk state.
+ /// Parse out a [`Summaries`] instances from on-disk state.
///
- /// This will attempt to prefer parsing a previous cache file that already
- /// exists from a previous invocation of Cargo (aka you're typing `cargo
- /// build` again after typing it previously). If parsing fails or the cache
- /// isn't found, then we take a slower path which loads the full descriptor
- /// for `relative` from the underlying index (aka typically libgit2 with
- /// crates.io) and then parse everything in there.
+ /// This will do the followings in order:
///
- /// * `root` - this is the root argument passed to `load`
- /// * `cache_root` - this is the root on the filesystem itself of where to
- /// store cache files.
- /// * `relative` - this is the file we're loading from cache or the index
+ /// 1. Attempt to prefer parsing a previous index cache file that already
+ /// exists from a previous invocation of Cargo (aka you're typing `cargo
+ /// build` again after typing it previously).
+ /// 2. If parsing fails, or the cache isn't found or is invalid, we then
+ /// take a slower path which loads the full descriptor for `relative`
+ /// from the underlying index (aka libgit2 with crates.io, or from a
+ /// remote HTTP index) and then parse everything in there.
+ ///
+ /// * `root` --- this is the root argument passed to `load`
+ /// * `cache_root` --- this is the root on the filesystem itself of where
+ /// to store cache files.
+ /// * `relative` --- this is the file we're loading from cache or the index
/// data
- /// * `source_id` - the registry's SourceId used when parsing JSON blobs to
- /// create summaries.
- /// * `load` - the actual index implementation which may be very slow to
+ /// * `source_id` --- the registry's SourceId used when parsing JSON blobs
+ /// to create summaries.
+ /// * `load` --- the actual index implementation which may be very slow to
/// call. We avoid this if we can.
pub fn parse(
root: &Path,
@@ -495,7 +711,7 @@ impl Summaries {
// allow future cargo implementations to break the
// interpretation of each line here and older cargo will simply
// ignore the new lines.
- let summary = match IndexSummary::parse(config, line, source_id) {
+ let summary = match IndexSummary::parse(line, source_id) {
Ok(summary) => summary,
Err(e) => {
// This should only happen when there is an index
@@ -549,8 +765,8 @@ impl Summaries {
}
}
- /// Parses an open `File` which represents information previously cached by
- /// Cargo.
+ /// Parses the contents of an on-disk cache, aka [`SummariesCache`], which
+ /// represents information previously cached by Cargo.
pub fn parse_cache(contents: Vec<u8>) -> CargoResult<(Summaries, InternedString)> {
let cache = SummariesCache::parse(&contents)?;
let index_version = InternedString::new(cache.index_version);
@@ -577,46 +793,8 @@ impl Summaries {
}
}
-// Implementation of serializing/deserializing the cache of summaries on disk.
-// Currently the format looks like:
-//
-// +--------------------+----------------------+-------------+---+
-// | cache version byte | index format version | git sha rev | 0 |
-// +--------------------+----------------------+-------------+---+
-//
-// followed by...
-//
-// +----------------+---+------------+---+
-// | semver version | 0 | JSON blob | 0 | ...
-// +----------------+---+------------+---+
-//
-// The idea is that this is a very easy file for Cargo to parse in future
-// invocations. The read from disk should be quite fast and then afterwards all
-// we need to know is what versions correspond to which JSON blob.
-//
-// The leading version byte is intended to ensure that there's some level of
-// future compatibility against changes to this cache format so if different
-// versions of Cargo share the same cache they don't get too confused. The git
-// sha lets us know when the file needs to be regenerated (it needs regeneration
-// whenever the index itself updates).
-//
-// Cache versions:
-// * `1`: The original version.
-// * `2`: Added the "index format version" field so that if the index format
-// changes, different versions of cargo won't get confused reading each
-// other's caches.
-// * `3`: Bumped the version to work around an issue where multiple versions of
-// a package were published that differ only by semver metadata. For
-// example, openssl-src 110.0.0 and 110.0.0+1.1.0f. Previously, the cache
-// would be incorrectly populated with two entries, both 110.0.0. After
-// this, the metadata will be correctly included. This isn't really a format
-// change, just a version bump to clear the incorrect cache entries. Note:
-// the index shouldn't allow these, but unfortunately crates.io doesn't
-// check it.
-
-const CURRENT_CACHE_VERSION: u8 = 3;
-
impl<'a> SummariesCache<'a> {
+ /// Deserializes an on-disk cache.
fn parse(data: &'a [u8]) -> CargoResult<SummariesCache<'a>> {
// NB: keep this method in sync with `serialize` below
let (first_byte, rest) = data
@@ -627,13 +805,11 @@ impl<'a> SummariesCache<'a> {
}
let index_v_bytes = rest
.get(..4)
- .ok_or_else(|| anyhow::anyhow!("cache expected 4 bytes for index version"))?;
+ .ok_or_else(|| anyhow::anyhow!("cache expected 4 bytes for index schema version"))?;
let index_v = u32::from_le_bytes(index_v_bytes.try_into().unwrap());
if index_v != INDEX_V_MAX {
bail!(
- "index format version {} doesn't match the version I know ({})",
- index_v,
- INDEX_V_MAX
+ "index schema version {index_v} doesn't match the version I know ({INDEX_V_MAX})",
);
}
let rest = &rest[4..];
@@ -655,6 +831,7 @@ impl<'a> SummariesCache<'a> {
Ok(ret)
}
+ /// Serializes itself with a given `index_version`.
fn serialize(&self, index_version: &str) -> Vec<u8> {
// NB: keep this method in sync with `parse` above
let size = self
@@ -683,17 +860,12 @@ impl MaybeIndexSummary {
/// Does nothing if this is already `Parsed`, and otherwise the `raw_data`
/// passed in is sliced with the bounds in `Unparsed` and then actually
/// parsed.
- fn parse(
- &mut self,
- config: &Config,
- raw_data: &[u8],
- source_id: SourceId,
- ) -> CargoResult<&IndexSummary> {
+ fn parse(&mut self, raw_data: &[u8], source_id: SourceId) -> CargoResult<&IndexSummary> {
let (start, end) = match self {
MaybeIndexSummary::Unparsed { start, end } => (*start, *end),
MaybeIndexSummary::Parsed(summary) => return Ok(summary),
};
- let summary = IndexSummary::parse(config, &raw_data[start..end], source_id)?;
+ let summary = IndexSummary::parse(&raw_data[start..end], source_id)?;
*self = MaybeIndexSummary::Parsed(summary);
match self {
MaybeIndexSummary::Unparsed { .. } => unreachable!(),
@@ -709,18 +881,19 @@ impl From<IndexSummary> for MaybeIndexSummary {
}
impl IndexSummary {
- /// Parses a line from the registry's index file into an `IndexSummary` for
- /// a package.
+ /// Parses a line from the registry's index file into an [`IndexSummary`]
+ /// for a package.
///
- /// The `line` provided is expected to be valid JSON.
- fn parse(config: &Config, line: &[u8], source_id: SourceId) -> CargoResult<IndexSummary> {
+ /// The `line` provided is expected to be valid JSON. It is supposed to be
+ /// a [`IndexPackage`].
+ fn parse(line: &[u8], source_id: SourceId) -> CargoResult<IndexSummary> {
// ****CAUTION**** Please be extremely careful with returning errors
// from this function. Entries that error are not included in the
// index cache, and can cause cargo to get confused when switching
// between different versions that understand the index differently.
// Make sure to consider the INDEX_V_MAX and CURRENT_CACHE_VERSION
// values carefully when making changes here.
- let RegistryPackage {
+ let IndexPackage {
name,
vers,
cksum,
@@ -744,7 +917,7 @@ impl IndexSummary {
features.entry(name).or_default().extend(values);
}
}
- let mut summary = Summary::new(config, pkgid, deps, &features, links, rust_version)?;
+ let mut summary = Summary::new(pkgid, deps, &features, links, rust_version)?;
summary.set_checksum(cksum);
Ok(IndexSummary {
summary,
@@ -754,6 +927,71 @@ impl IndexSummary {
}
}
+impl<'a> RegistryDependency<'a> {
+ /// Converts an encoded dependency in the registry to a cargo dependency
+ pub fn into_dep(self, default: SourceId) -> CargoResult<Dependency> {
+ let RegistryDependency {
+ name,
+ req,
+ mut features,
+ optional,
+ default_features,
+ target,
+ kind,
+ registry,
+ package,
+ public,
+ } = self;
+
+ let id = if let Some(registry) = &registry {
+ SourceId::for_registry(&registry.into_url()?)?
+ } else {
+ default
+ };
+
+ let mut dep = Dependency::parse(package.unwrap_or(name), Some(&req), id)?;
+ if package.is_some() {
+ dep.set_explicit_name_in_toml(name);
+ }
+ let kind = match kind.as_deref().unwrap_or("") {
+ "dev" => DepKind::Development,
+ "build" => DepKind::Build,
+ _ => DepKind::Normal,
+ };
+
+ let platform = match target {
+ Some(target) => Some(target.parse()?),
+ None => None,
+ };
+
+ // All dependencies are private by default
+ let public = public.unwrap_or(false);
+
+ // Unfortunately older versions of cargo and/or the registry ended up
+ // publishing lots of entries where the features array contained the
+ // empty feature, "", inside. This confuses the resolution process much
+ // later on and these features aren't actually valid, so filter them all
+ // out here.
+ features.retain(|s| !s.is_empty());
+
+ // In index, "registry" is null if it is from the same index.
+ // In Cargo.toml, "registry" is None if it is from the default
+ if !id.is_crates_io() {
+ dep.set_registry_id(id);
+ }
+
+ dep.set_optional(optional)
+ .set_default_features(default_features)
+ .set_features(features)
+ .set_platform(platform)
+ .set_kind(kind)
+ .set_public(public);
+
+ Ok(dep)
+ }
+}
+
+/// Like [`slice::split`] but is optimized by [`memchr`].
fn split(haystack: &[u8], needle: u8) -> impl Iterator<Item = &[u8]> {
struct Split<'a> {
haystack: &'a [u8],
@@ -778,3 +1016,36 @@ fn split(haystack: &[u8], needle: u8) -> impl Iterator<Item = &[u8]> {
Split { haystack, needle }
}
+
+#[test]
+fn escaped_char_in_index_json_blob() {
+ let _: IndexPackage<'_> = serde_json::from_str(
+ r#"{"name":"a","vers":"0.0.1","deps":[],"cksum":"bae3","features":{}}"#,
+ )
+ .unwrap();
+ let _: IndexPackage<'_> = serde_json::from_str(
+ r#"{"name":"a","vers":"0.0.1","deps":[],"cksum":"bae3","features":{"test":["k","q"]},"links":"a-sys"}"#
+ ).unwrap();
+
+ // Now we add escaped cher all the places they can go
+ // these are not valid, but it should error later than json parsing
+ let _: IndexPackage<'_> = serde_json::from_str(
+ r#"{
+ "name":"This name has a escaped cher in it \n\t\" ",
+ "vers":"0.0.1",
+ "deps":[{
+ "name": " \n\t\" ",
+ "req": " \n\t\" ",
+ "features": [" \n\t\" "],
+ "optional": true,
+ "default_features": true,
+ "target": " \n\t\" ",
+ "kind": " \n\t\" ",
+ "registry": " \n\t\" "
+ }],
+ "cksum":"bae3",
+ "features":{"test \n\t\" ":["k \n\t\" ","q \n\t\" "]},
+ "links":" \n\t\" "}"#,
+ )
+ .unwrap();
+}
diff --git a/src/tools/cargo/src/cargo/sources/registry/local.rs b/src/tools/cargo/src/cargo/sources/registry/local.rs
index 89419191f..68fc61a6c 100644
--- a/src/tools/cargo/src/cargo/sources/registry/local.rs
+++ b/src/tools/cargo/src/cargo/sources/registry/local.rs
@@ -1,3 +1,5 @@
+//! Access to a regstiry on the local filesystem. See [`LocalRegistry`] for more.
+
use crate::core::PackageId;
use crate::sources::registry::{LoadResponse, MaybeLock, RegistryConfig, RegistryData};
use crate::util::errors::CargoResult;
@@ -10,18 +12,68 @@ use std::path::Path;
use std::task::Poll;
/// A local registry is a registry that lives on the filesystem as a set of
-/// `.crate` files with an `index` directory in the same format as a remote
+/// `.crate` files with an `index` directory in the [same format] as a remote
/// registry.
+///
+/// This type is primarily accessed through the [`RegistryData`] trait.
+///
+/// When a local registry is requested for a package, it simply looks into what
+/// its index has under the `index` directory. When [`LocalRegistry::download`]
+/// is called, a local registry verifies the checksum of the requested `.crate`
+/// tarball and then unpacks it to `$CARGO_HOME/.registry/src`.
+///
+/// > Note that there is a third-party subcommand [`cargo-local-registry`],
+/// > which happened to be developed by a former Cargo team member when local
+/// > registry was introduced. The tool is to ease the burden of maintaining
+/// > local registries. However, in general the Cargo team avoids recommending
+/// > any specific third-party crate. Just FYI.
+///
+/// [same format]: super#the-format-of-the-index
+/// [`cargo-local-registry`]: https://crates.io/crates/cargo-local-registry
+///
+/// # Filesystem hierarchy
+///
+/// Here is an example layout of a local registry on a local filesystem:
+///
+/// ```text
+/// [registry root]/
+/// ├── index/ # registry index
+/// │ ├── an/
+/// │ │ └── yh/
+/// │ │ └── anyhow
+/// │ ├── ru/
+/// │ │ └── st/
+/// │ │ ├── rustls
+/// │ │ └── rustls-ffi
+/// │ └── se/
+/// │ └── mv/
+/// │ └── semver
+/// ├── anyhow-1.0.71.crate # pre-downloaded crate tarballs
+/// ├── rustls-0.20.8.crate
+/// ├── rustls-ffi-0.8.2.crate
+/// └── semver-1.0.17.crate
+/// ```
+///
+/// For general concepts of registries, see the [module-level documentation](crate::sources::registry).
pub struct LocalRegistry<'cfg> {
+ /// Path to the registry index.
index_path: Filesystem,
+ /// Root path of this local registry.
root: Filesystem,
+ /// Path where this local registry extract `.crate` tarballs to.
src_path: Filesystem,
config: &'cfg Config,
+ /// Whether this source has updated all package informations it may contain.
updated: bool,
+ /// Disables status messages.
quiet: bool,
}
impl<'cfg> LocalRegistry<'cfg> {
+ /// Creates a local registry at `root`.
+ ///
+ /// * `name` --- Name of a path segment where `.crate` tarballs are stored.
+ /// Expect to be unique.
pub fn new(root: &Path, config: &'cfg Config, name: &str) -> LocalRegistry<'cfg> {
LocalRegistry {
src_path: config.registry_source_path().join(name),
@@ -115,17 +167,15 @@ impl<'cfg> RegistryData for LocalRegistry<'cfg> {
}
fn download(&mut self, pkg: PackageId, checksum: &str) -> CargoResult<MaybeLock> {
- let crate_file = format!("{}-{}.crate", pkg.name(), pkg.version());
-
// Note that the usage of `into_path_unlocked` here is because the local
// crate files here never change in that we're not the one writing them,
// so it's not our responsibility to synchronize access to them.
- let path = self.root.join(&crate_file).into_path_unlocked();
+ let path = self.root.join(&pkg.tarball_name()).into_path_unlocked();
let mut crate_file = paths::open(&path)?;
// If we've already got an unpacked version of this crate, then skip the
// checksum below as it is in theory already verified.
- let dst = format!("{}-{}", pkg.name(), pkg.version());
+ let dst = path.file_stem().unwrap();
if self.src_path.join(dst).into_path_unlocked().exists() {
return Ok(MaybeLock::Ready(crate_file));
}
diff --git a/src/tools/cargo/src/cargo/sources/registry/mod.rs b/src/tools/cargo/src/cargo/sources/registry/mod.rs
index c76ee6142..a0178db55 100644
--- a/src/tools/cargo/src/cargo/sources/registry/mod.rs
+++ b/src/tools/cargo/src/cargo/sources/registry/mod.rs
@@ -2,13 +2,47 @@
//!
//! # What's a Registry?
//!
-//! Registries are central locations where packages can be uploaded to,
+//! [Registries] are central locations where packages can be uploaded to,
//! discovered, and searched for. The purpose of a registry is to have a
//! location that serves as permanent storage for versions of a crate over time.
//!
-//! Compared to git sources, a registry provides many packages as well as many
-//! versions simultaneously. Git sources can also have commits deleted through
-//! rebasings where registries cannot have their versions deleted.
+//! Compared to git sources (see [`GitSource`]), a registry provides many
+//! packages as well as many versions simultaneously. Git sources can also
+//! have commits deleted through rebasings where registries cannot have their
+//! versions deleted.
+//!
+//! In Cargo, [`RegistryData`] is an abstraction over each kind of actual
+//! registry, and [`RegistrySource`] connects those implementations to
+//! [`Source`] trait. Two prominent features these abstractions provide are
+//!
+//! * A way to query the metadata of a package from a registry. The metadata
+//! comes from the index.
+//! * A way to download package contents (a.k.a source files) that are required
+//! when building the package itself.
+//!
+//! We'll cover each functionality later.
+//!
+//! [Registries]: https://doc.rust-lang.org/nightly/cargo/reference/registries.html
+//! [`GitSource`]: super::GitSource
+//!
+//! # Different Kinds of Registries
+//!
+//! Cargo provides multiple kinds of registries. Each of them serves the index
+//! and package contents in a slightly different way. Namely,
+//!
+//! * [`LocalRegistry`] --- Serves the index and package contents entirely on
+//! a local filesystem.
+//! * [`RemoteRegistry`] --- Serves the index ahead of time from a Git
+//! repository, and package contents are downloaded as needed.
+//! * [`HttpRegistry`] --- Serves both the index and package contents on demand
+//! over a HTTP-based registry API. This is the default starting from 1.70.0.
+//!
+//! Each registry has its own [`RegistryData`] implementation, and can be
+//! created from either [`RegistrySource::local`] or [`RegistrySource::remote`].
+//!
+//! [`LocalRegistry`]: local::LocalRegistry
+//! [`RemoteRegistry`]: remote::RemoteRegistry
+//! [`HttpRegistry`]: http_remote::HttpRegistry
//!
//! # The Index of a Registry
//!
@@ -20,36 +54,16 @@
//! available on a registry, what versions are available, and what the
//! dependencies for each version is.
//!
-//! One method of doing so would be having the registry expose an HTTP endpoint
-//! which can be queried with a list of packages and a response of their
-//! dependencies and versions is returned. This is somewhat inefficient however
-//! as we may have to hit the endpoint many times and we may have already
-//! queried for much of the data locally already (for other packages, for
-//! example). This also involves inventing a transport format between the
-//! registry and Cargo itself, so this route was not taken.
-//!
-//! Instead, Cargo communicates with registries through a git repository
-//! referred to as the Index. The Index of a registry is essentially an easily
-//! query-able version of the registry's database for a list of versions of a
-//! package as well as a list of dependencies for each version.
+//! To solve the problem, a registry must provide an index of package metadata.
+//! The index of a registry is essentially an easily query-able version of the
+//! registry's database for a list of versions of a package as well as a list
+//! of dependencies for each version. The exact format of the index is
+//! described later.
//!
-//! Using git to host this index provides a number of benefits:
+//! See the [`index`] module for topics about the management, parsing, caching,
+//! and versioning for the on-disk index.
//!
-//! * The entire index can be stored efficiently locally on disk. This means
-//! that all queries of a registry can happen locally and don't need to touch
-//! the network.
-//!
-//! * Updates of the index are quite efficient. Using git buys incremental
-//! updates, compressed transmission, etc for free. The index must be updated
-//! each time we need fresh information from a registry, but this is one
-//! update of a git repository that probably hasn't changed a whole lot so
-//! it shouldn't be too expensive.
-//!
-//! Additionally, each modification to the index is just appending a line at
-//! the end of a file (the exact format is described later). This means that
-//! the commits for an index are quite small and easily applied/compressible.
-//!
-//! ## The format of the Index
+//! ## The Format of The Index
//!
//! The index is a store for the list of versions for all packages known, so its
//! format on disk is optimized slightly to ensure that `ls registry` doesn't
@@ -59,9 +73,12 @@
//! about the format of the registry:
//!
//! 1. Each crate will have one file corresponding to it. Each version for a
-//! crate will just be a line in this file.
+//! crate will just be a line in this file (see [`IndexPackage`] for its
+//! representation).
//! 2. There will be two tiers of directories for crate names, under which
//! crates corresponding to those tiers will be located.
+//! (See [`cargo_util::registry::make_dep_path`] for the implementation of
+//! this layout hierarchy.)
//!
//! As an example, this is an example hierarchy of an index:
//!
@@ -99,26 +116,30 @@
//! The purpose of this layout is to hopefully cut down on `ls` sizes as well as
//! efficient lookup based on the crate name itself.
//!
-//! ## Crate files
+//! See [The Cargo Book: Registry Index][registry-index] for the public
+//! interface on the index format.
+//!
+//! [registry-index]: https://doc.rust-lang.org/nightly/cargo/reference/registry-index.html
+//!
+//! ## The Index Files
//!
//! Each file in the index is the history of one crate over time. Each line in
//! the file corresponds to one version of a crate, stored in JSON format (see
-//! the `RegistryPackage` structure below).
+//! the [`IndexPackage`] structure).
//!
-//! As new versions are published, new lines are appended to this file. The only
-//! modifications to this file that should happen over time are yanks of a
-//! particular version.
+//! As new versions are published, new lines are appended to this file. **The
+//! only modifications to this file that should happen over time are yanks of a
+//! particular version.**
//!
//! # Downloading Packages
//!
-//! The purpose of the Index was to provide an efficient method to resolve the
-//! dependency graph for a package. So far we only required one network
-//! interaction to update the registry's repository (yay!). After resolution has
-//! been performed, however we need to download the contents of packages so we
-//! can read the full manifest and build the source code.
+//! The purpose of the index was to provide an efficient method to resolve the
+//! dependency graph for a package. After resolution has been performed, we need
+//! to download the contents of packages so we can read the full manifest and
+//! build the source code.
//!
-//! To accomplish this, this source's `download` method will make an HTTP
-//! request per-package requested to download tarballs into a local cache. These
+//! To accomplish this, [`RegistryData::download`] will "make" an HTTP request
+//! per-package requested to download tarballs into a local cache. These
//! tarballs will then be unpacked into a destination folder.
//!
//! Note that because versions uploaded to the registry are frozen forever that
@@ -128,7 +149,8 @@
//!
//! # Filesystem Hierarchy
//!
-//! Overall, the `$HOME/.cargo` looks like this when talking about the registry:
+//! Overall, the `$HOME/.cargo` looks like this when talking about the registry
+//! (remote registries, specifically):
//!
//! ```notrust
//! # A folder under which all registry metadata is hosted (similar to
@@ -144,8 +166,8 @@
//! registry2-<hash>/
//! ...
//!
-//! # This folder is a cache for all downloaded tarballs from a registry.
-//! # Once downloaded and verified, a tarball never changes.
+//! # This folder is a cache for all downloaded tarballs (`.crate` file)
+//! # from a registry. Once downloaded and verified, a tarball never changes.
//! cache/
//! registry1-<hash>/<pkg>-<version>.crate
//! ...
@@ -153,13 +175,14 @@
//! # Location in which all tarballs are unpacked. Each tarball is known to
//! # be frozen after downloading, so transitively this folder is also
//! # frozen once its unpacked (it's never unpacked again)
+//! # CAVEAT: They are not read-only. See rust-lang/cargo#9455.
//! src/
//! registry1-<hash>/<pkg>-<version>/...
//! ...
//! ```
+//!
+//! [`IndexPackage`]: index::IndexPackage
-use std::borrow::Cow;
-use std::collections::BTreeMap;
use std::collections::HashSet;
use std::fs;
use std::fs::{File, OpenOptions};
@@ -173,35 +196,30 @@ use anyhow::Context as _;
use cargo_util::paths::{self, exclude_from_backups_and_indexing};
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};
+use crate::core::dependency::Dependency;
use crate::core::source::MaybePackage;
use crate::core::{Package, PackageId, QueryKind, Source, SourceId, Summary};
use crate::sources::PathSource;
use crate::util::hex;
-use crate::util::interning::InternedString;
-use crate::util::into_url::IntoUrl;
use crate::util::network::PollExt;
use crate::util::{
restricted_names, CargoResult, Config, Filesystem, LimitErrorReader, OptVersionReq,
};
+/// The `.cargo-ok` file is used to track if the source is already unpacked.
+/// See [`RegistrySource::unpack_package`] for more.
+///
+/// Not to be confused with `.cargo-ok` file in git sources.
const PACKAGE_SOURCE_LOCK: &str = ".cargo-ok";
+
pub const CRATES_IO_INDEX: &str = "https://github.com/rust-lang/crates.io-index";
pub const CRATES_IO_HTTP_INDEX: &str = "sparse+https://index.crates.io/";
pub const CRATES_IO_REGISTRY: &str = "crates-io";
pub const CRATES_IO_DOMAIN: &str = "crates.io";
-const CRATE_TEMPLATE: &str = "{crate}";
-const VERSION_TEMPLATE: &str = "{version}";
-const PREFIX_TEMPLATE: &str = "{prefix}";
-const LOWER_PREFIX_TEMPLATE: &str = "{lowerprefix}";
-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.
@@ -211,13 +229,15 @@ struct LockMetadata {
v: u32,
}
-/// A "source" for a local (see `local::LocalRegistry`) or remote (see
-/// `remote::RemoteRegistry`) registry.
+/// A [`Source`] implementation for a local or a remote registry.
///
-/// This contains common functionality that is shared between the two registry
-/// kinds, with the registry-specific logic implemented as part of the
+/// This contains common functionality that is shared between each registry
+/// kind, with the registry-specific logic implemented as part of the
/// [`RegistryData`] trait referenced via the `ops` field.
+///
+/// For general concepts of registries, see the [module-level documentation](crate::sources::registry).
pub struct RegistrySource<'cfg> {
+ /// The unique identifier of this source.
source_id: SourceId,
/// The path where crate files are extracted (`$CARGO_HOME/registry/src/$REG-HASH`).
src_path: Filesystem,
@@ -237,7 +257,19 @@ pub struct RegistrySource<'cfg> {
yanked_whitelist: HashSet<PackageId>,
}
-/// The `config.json` file stored in the index.
+/// The [`config.json`] file stored in the index.
+///
+/// The config file may look like:
+///
+/// ```json
+/// {
+/// "dl": "https://example.com/api/{crate}/{version}/download",
+/// "api": "https://example.com/api",
+/// "auth-required": false # unstable feature (RFC 3139)
+/// }
+/// ```
+///
+/// [`config.json`]: https://doc.rust-lang.org/nightly/cargo/reference/registry-index.html#index-configuration
#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "kebab-case")]
pub struct RegistryConfig {
@@ -257,6 +289,9 @@ pub struct RegistryConfig {
/// will be extended with `/{crate}/{version}/download` to
/// support registries like crates.io which were created before the
/// templating setup was created.
+ ///
+ /// For more on the template of the download URL, see [Index Configuration](
+ /// https://doc.rust-lang.org/nightly/cargo/reference/registry-index.html#index-configuration).
pub dl: String,
/// API endpoint for the registry. This is what's actually hit to perform
@@ -264,183 +299,13 @@ pub struct RegistryConfig {
/// If this is None, the registry does not support API commands.
pub api: Option<String>,
- /// Whether all operations require authentication.
+ /// Whether all operations require authentication. See [RFC 3139].
+ ///
+ /// [RFC 3139]: https://rust-lang.github.io/rfcs/3139-cargo-alternative-registry-auth.html
#[serde(default)]
pub auth_required: bool,
}
-/// The maximum version of the `v` field in the index this version of cargo
-/// understands.
-pub(crate) const INDEX_V_MAX: u32 = 2;
-
-/// A single line in the index representing a single version of a package.
-#[derive(Deserialize)]
-pub struct RegistryPackage<'a> {
- name: InternedString,
- vers: Version,
- #[serde(borrow)]
- deps: Vec<RegistryDependency<'a>>,
- features: BTreeMap<InternedString, Vec<InternedString>>,
- /// This field contains features with new, extended syntax. Specifically,
- /// namespaced features (`dep:`) and weak dependencies (`pkg?/feat`).
- ///
- /// This is separated from `features` because versions older than 1.19
- /// will fail to load due to not being able to parse the new syntax, even
- /// with a `Cargo.lock` file.
- features2: Option<BTreeMap<InternedString, Vec<InternedString>>>,
- cksum: String,
- /// If `true`, Cargo will skip this version when resolving.
- ///
- /// This was added in 2014. Everything in the crates.io index has this set
- /// now, so this probably doesn't need to be an option anymore.
- yanked: Option<bool>,
- /// Native library name this package links to.
- ///
- /// 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
- /// versions are ignored.
- ///
- /// Version `2` format adds the `features2` field.
- ///
- /// This provides a method to safely introduce changes to index entries
- /// and allow older versions of cargo to ignore newer entries it doesn't
- /// understand. This is honored as of 1.51, so unfortunately older
- /// versions will ignore it, and potentially misinterpret version 2 and
- /// newer entries.
- ///
- /// The intent is that versions older than 1.51 will work with a
- /// pre-existing `Cargo.lock`, but they may not correctly process `cargo
- /// update` or build a lock from scratch. In that case, cargo may
- /// incorrectly select a new package that uses a new index format. A
- /// workaround is to downgrade any packages that are incompatible with the
- /// `--precise` flag of `cargo update`.
- v: Option<u32>,
-}
-
-#[test]
-fn escaped_char_in_json() {
- let _: RegistryPackage<'_> = serde_json::from_str(
- r#"{"name":"a","vers":"0.0.1","deps":[],"cksum":"bae3","features":{}}"#,
- )
- .unwrap();
- let _: RegistryPackage<'_> = serde_json::from_str(
- r#"{"name":"a","vers":"0.0.1","deps":[],"cksum":"bae3","features":{"test":["k","q"]},"links":"a-sys"}"#
- ).unwrap();
-
- // Now we add escaped cher all the places they can go
- // these are not valid, but it should error later than json parsing
- let _: RegistryPackage<'_> = serde_json::from_str(
- r#"{
- "name":"This name has a escaped cher in it \n\t\" ",
- "vers":"0.0.1",
- "deps":[{
- "name": " \n\t\" ",
- "req": " \n\t\" ",
- "features": [" \n\t\" "],
- "optional": true,
- "default_features": true,
- "target": " \n\t\" ",
- "kind": " \n\t\" ",
- "registry": " \n\t\" "
- }],
- "cksum":"bae3",
- "features":{"test \n\t\" ":["k \n\t\" ","q \n\t\" "]},
- "links":" \n\t\" "}"#,
- )
- .unwrap();
-}
-
-/// A dependency as encoded in the index JSON.
-#[derive(Deserialize)]
-struct RegistryDependency<'a> {
- name: InternedString,
- #[serde(borrow)]
- req: Cow<'a, str>,
- features: Vec<InternedString>,
- optional: bool,
- default_features: bool,
- target: Option<Cow<'a, str>>,
- kind: Option<Cow<'a, str>>,
- registry: Option<Cow<'a, str>>,
- package: Option<InternedString>,
- public: Option<bool>,
-}
-
-impl<'a> RegistryDependency<'a> {
- /// Converts an encoded dependency in the registry to a cargo dependency
- pub fn into_dep(self, default: SourceId) -> CargoResult<Dependency> {
- let RegistryDependency {
- name,
- req,
- mut features,
- optional,
- default_features,
- target,
- kind,
- registry,
- package,
- public,
- } = self;
-
- let id = if let Some(registry) = &registry {
- SourceId::for_registry(&registry.into_url()?)?
- } else {
- default
- };
-
- let mut dep = Dependency::parse(package.unwrap_or(name), Some(&req), id)?;
- if package.is_some() {
- dep.set_explicit_name_in_toml(name);
- }
- let kind = match kind.as_deref().unwrap_or("") {
- "dev" => DepKind::Development,
- "build" => DepKind::Build,
- _ => DepKind::Normal,
- };
-
- let platform = match target {
- Some(target) => Some(target.parse()?),
- None => None,
- };
-
- // All dependencies are private by default
- let public = public.unwrap_or(false);
-
- // Unfortunately older versions of cargo and/or the registry ended up
- // publishing lots of entries where the features array contained the
- // empty feature, "", inside. This confuses the resolution process much
- // later on and these features aren't actually valid, so filter them all
- // out here.
- features.retain(|s| !s.is_empty());
-
- // In index, "registry" is null if it is from the same index.
- // In Cargo.toml, "registry" is None if it is from the default
- if !id.is_crates_io() {
- dep.set_registry_id(id);
- }
-
- dep.set_optional(optional)
- .set_default_features(default_features)
- .set_features(features)
- .set_platform(platform)
- .set_kind(kind)
- .set_public(public);
-
- Ok(dep)
- }
-}
-
/// Result from loading data from a registry.
pub enum LoadResponse {
/// The cache is valid. The cached data should be used.
@@ -449,6 +314,7 @@ pub enum LoadResponse {
/// The cache is out of date. Returned data should be used.
Data {
raw_data: Vec<u8>,
+ /// Version of this data to determine whether it is out of date.
index_version: Option<String>,
},
@@ -456,10 +322,11 @@ pub enum LoadResponse {
NotFound,
}
-/// An abstract interface to handle both a local (see `local::LocalRegistry`)
-/// and remote (see `remote::RemoteRegistry`) registry.
+/// An abstract interface to handle both a local and and remote registry.
///
-/// This allows [`RegistrySource`] to abstractly handle both registry kinds.
+/// This allows [`RegistrySource`] to abstractly handle each registry kind.
+///
+/// For general concepts of registries, see the [module-level documentation](crate::sources::registry).
pub trait RegistryData {
/// Performs initialization for the registry.
///
@@ -470,14 +337,15 @@ pub trait RegistryData {
/// Returns the path to the index.
///
/// Note that different registries store the index in different formats
- /// (remote=git, local=files).
+ /// (remote = git, http & local = files).
fn index_path(&self) -> &Filesystem;
/// Loads the JSON for a specific named package from the index.
///
/// * `root` is the root path to the index.
/// * `path` is the relative path to the package to load (like `ca/rg/cargo`).
- /// * `index_version` is the version of the requested crate data currently in cache.
+ /// * `index_version` is the version of the requested crate data currently
+ /// in cache. This is useful for checking if a local cache is outdated.
fn load(
&mut self,
root: &Path,
@@ -568,6 +436,8 @@ mod index;
mod local;
mod remote;
+/// Generates a unique name for [`SourceId`] to have a unique path to put their
+/// index files.
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();
@@ -579,6 +449,11 @@ fn short_name(id: SourceId, is_shallow: bool) -> String {
}
impl<'cfg> RegistrySource<'cfg> {
+ /// Creates a [`Source`] of a "remote" registry.
+ /// It could be either an HTTP-based [`http_remote::HttpRegistry`] or
+ /// a Git-based [`remote::RemoteRegistry`].
+ ///
+ /// * `yanked_whitelist` --- Packages allowed to be used, even if they are yanked.
pub fn remote(
source_id: SourceId,
yanked_whitelist: &HashSet<PackageId>,
@@ -608,6 +483,10 @@ impl<'cfg> RegistrySource<'cfg> {
))
}
+ /// Creates a [`Source`] of a local registry, with [`local::LocalRegistry`] under the hood.
+ ///
+ /// * `path` --- The root path of a local registry on the file system.
+ /// * `yanked_whitelist` --- Packages allowed to be used, even if they are yanked.
pub fn local(
source_id: SourceId,
path: &Path,
@@ -619,6 +498,12 @@ impl<'cfg> RegistrySource<'cfg> {
RegistrySource::new(source_id, config, &name, Box::new(ops), yanked_whitelist)
}
+ /// Creates a source of a registry. This is a inner helper function.
+ ///
+ /// * `name` --- Name of a path segment which may affect where `.crate`
+ /// tarballs, the registry index and cache are stored. Expect to be unique.
+ /// * `ops` --- The underlying [`RegistryData`] type.
+ /// * `yanked_whitelist` --- Packages allowed to be used, even if they are yanked.
fn new(
source_id: SourceId,
config: &'cfg Config,
@@ -636,7 +521,7 @@ impl<'cfg> RegistrySource<'cfg> {
}
}
- /// Decode the configuration stored within the registry.
+ /// Decode the [configuration](RegistryConfig) stored within the registry.
///
/// This requires that the index has been at least checked out.
pub fn config(&mut self) -> Poll<CargoResult<Option<RegistryConfig>>> {
@@ -692,8 +577,6 @@ impl<'cfg> RegistrySource<'cfg> {
///
/// [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.
let package_dir = format!("{}-{}", pkg.name(), pkg.version());
let dst = self.src_path.join(&package_dir);
let path = dst.join(PACKAGE_SOURCE_LOCK);
@@ -786,6 +669,12 @@ impl<'cfg> RegistrySource<'cfg> {
Ok(unpack_dir.to_path_buf())
}
+ /// Turns the downloaded `.crate` tarball file into a [`Package`].
+ ///
+ /// This unconditionally sets checksum for the returned package, so it
+ /// should only be called after doing integrity check. That is to say,
+ /// you need to call either [`RegistryData::download`] or
+ /// [`RegistryData::finish_download`] before calling this method.
fn get_pkg(&mut self, package: PackageId, path: &File) -> CargoResult<Package> {
let path = self
.unpack_package(package, path)
@@ -996,6 +885,11 @@ impl<'cfg> Source for RegistrySource<'cfg> {
}
}
+impl RegistryConfig {
+ /// File name of [`RegistryConfig`].
+ const NAME: &str = "config.json";
+}
+
/// Get the maximum upack size that Cargo permits
/// based on a given `size` of your compressed file.
///
@@ -1017,6 +911,9 @@ impl<'cfg> Source for RegistrySource<'cfg> {
fn max_unpack_size(config: &Config, size: u64) -> u64 {
const SIZE_VAR: &str = "__CARGO_TEST_MAX_UNPACK_SIZE";
const RATIO_VAR: &str = "__CARGO_TEST_MAX_UNPACK_RATIO";
+ const MAX_UNPACK_SIZE: u64 = 512 * 1024 * 1024; // 512 MiB
+ const MAX_COMPRESSION_RATIO: usize = 20; // 20:1
+
let max_unpack_size = if cfg!(debug_assertions) && config.get_env(SIZE_VAR).is_ok() {
// For integration test only.
config
@@ -1041,30 +938,6 @@ fn max_unpack_size(config: &Config, size: u64) -> u64 {
u64::max(max_unpack_size, size * max_compression_ratio as u64)
}
-fn make_dep_prefix(name: &str) -> String {
- match name.len() {
- 1 => String::from("1"),
- 2 => String::from("2"),
- 3 => format!("3/{}", &name[..1]),
- _ => format!("{}/{}", &name[0..2], &name[2..4]),
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::make_dep_prefix;
-
- #[test]
- fn dep_prefix() {
- assert_eq!(make_dep_prefix("a"), "1");
- assert_eq!(make_dep_prefix("ab"), "2");
- assert_eq!(make_dep_prefix("abc"), "3/a");
- assert_eq!(make_dep_prefix("Abc"), "3/A");
- assert_eq!(make_dep_prefix("AbCd"), "Ab/Cd");
- assert_eq!(make_dep_prefix("aBcDe"), "aB/cD");
- }
-}
-
/// Set the current [`umask`] value for the given tarball. No-op on non-Unix
/// platforms.
///
diff --git a/src/tools/cargo/src/cargo/sources/registry/remote.rs b/src/tools/cargo/src/cargo/sources/registry/remote.rs
index f4df4e86b..4223b0303 100644
--- a/src/tools/cargo/src/cargo/sources/registry/remote.rs
+++ b/src/tools/cargo/src/cargo/sources/registry/remote.rs
@@ -1,3 +1,5 @@
+//! Access to a Git index based registry. See [`RemoteRegistry`] for details.
+
use crate::core::{GitReference, PackageId, SourceId};
use crate::sources::git;
use crate::sources::git::fetch::RemoteKind;
@@ -21,29 +23,73 @@ use std::task::{ready, Poll};
/// A remote registry is a registry that lives at a remote URL (such as
/// crates.io). The git index is cloned locally, and `.crate` files are
/// downloaded as needed and cached locally.
+///
+/// This type is primarily accessed through the [`RegistryData`] trait.
+///
+/// See the [module-level documentation](super) for the index format and layout.
+///
+/// ## History of Git-based index registry
+///
+/// Using Git to host this index used to be quite efficient. The full index can
+/// be stored efficiently locally on disk, and once it is downloaded, all
+/// queries of a registry can happen locally and needn't touch the network.
+/// Git-based index was a reasonable design choice at the time when HTTP/2
+/// was just introduced.
+///
+/// However, the full index keeps growing as crates.io grows. It becomes
+/// relatively big and slows down the first use of Cargo. Git (specifically
+/// libgit2) is not efficient at handling huge amounts of small files either.
+/// On the other hand, newer protocols like HTTP/2 are prevalent and capable to
+/// serve a bunch of tiny files. Today, it is encouraged to use [`HttpRegistry`],
+/// which is the default from 1.70.0. That being said, Cargo will continue
+/// supporting Git-based index for a pretty long while.
+///
+/// [`HttpRegistry`]: super::http_remote::HttpRegistry
pub struct RemoteRegistry<'cfg> {
+ /// Path to the registry index (`$CARGO_HOME/registry/index/$REG-HASH`).
index_path: Filesystem,
- /// Path to the cache of `.crate` files (`$CARGO_HOME/registry/path/$REG-HASH`).
+ /// Path to the cache of `.crate` files (`$CARGO_HOME/registry/cache/$REG-HASH`).
cache_path: Filesystem,
+ /// The unique identifier of this registry source.
source_id: SourceId,
+ /// This reference is stored so that when a registry needs update, it knows
+ /// where to fetch from.
index_git_ref: GitReference,
config: &'cfg Config,
+ /// A Git [tree object] to help this registry find crate metadata from the
+ /// underlying Git repository.
+ ///
+ /// This is stored here to prevent Git from repeatly creating a tree object
+ /// during each call into `load()`.
+ ///
+ /// [tree object]: https://git-scm.com/book/en/v2/Git-Internals-Git-Objects#_tree_objects
tree: RefCell<Option<git2::Tree<'static>>>,
+ /// A Git repository that contains the actual index we want.
repo: LazyCell<git2::Repository>,
+ /// The current HEAD commit of the underlying Git repository.
head: Cell<Option<git2::Oid>>,
+ /// This stores sha value of the current HEAD commit for convenience.
current_sha: Cell<Option<InternedString>>,
- needs_update: bool, // Does this registry need to be updated?
+ /// Whether this registry needs to update package informations.
+ ///
+ /// See [`RemoteRegistry::mark_updated`] on how to make sure a registry
+ /// index is updated only once per session.
+ needs_update: bool,
+ /// Disables status messages.
quiet: bool,
}
impl<'cfg> RemoteRegistry<'cfg> {
+ /// Creates a Git-rebased remote registry for `source_id`.
+ ///
+ /// * `name` --- Name of a path segment where `.crate` tarballs and the
+ /// registry index are stored. Expect to be unique.
pub fn new(source_id: SourceId, config: &'cfg Config, name: &str) -> RemoteRegistry<'cfg> {
RemoteRegistry {
index_path: config.registry_index_path().join(name),
cache_path: config.registry_cache_path().join(name),
source_id,
config,
- // TODO: we should probably make this configurable
index_git_ref: GitReference::DefaultBranch,
tree: RefCell::new(None),
repo: LazyCell::new(),
@@ -54,18 +100,12 @@ impl<'cfg> RemoteRegistry<'cfg> {
}
}
+ /// Creates intermediate dirs and initialize the repository.
fn repo(&self) -> CargoResult<&git2::Repository> {
self.repo.try_borrow_with(|| {
+ trace!("acquiring registry index lock");
let path = self.config.assert_package_cache_locked(&self.index_path);
- // Fast path without a lock
- if let Ok(repo) = git2::Repository::open(&path) {
- trace!("opened a repo without a lock");
- return Ok(repo);
- }
-
- // Ok, now we need to lock and try the whole thing over again.
- trace!("acquiring registry index lock");
match git2::Repository::open(&path) {
Ok(repo) => Ok(repo),
Err(_) => {
@@ -97,6 +137,7 @@ impl<'cfg> RemoteRegistry<'cfg> {
})
}
+ /// Get the object ID of the HEAD commit from the underlying Git repository.
fn head(&self) -> CargoResult<git2::Oid> {
if self.head.get().is_none() {
let repo = self.repo()?;
@@ -106,6 +147,8 @@ impl<'cfg> RemoteRegistry<'cfg> {
Ok(self.head.get().unwrap())
}
+ /// Returns a [`git2::Tree`] object of the current HEAD commit of the
+ /// underlying Git repository.
fn tree(&self) -> CargoResult<Ref<'_, git2::Tree<'_>>> {
{
let tree = self.tree.borrow();
@@ -117,6 +160,7 @@ impl<'cfg> RemoteRegistry<'cfg> {
let commit = repo.find_commit(self.head()?)?;
let tree = commit.tree()?;
+ // SAFETY:
// Unfortunately in libgit2 the tree objects look like they've got a
// reference to the repository object which means that a tree cannot
// outlive the repository that it came from. Here we want to cache this
@@ -134,6 +178,9 @@ impl<'cfg> RemoteRegistry<'cfg> {
Ok(Ref::map(self.tree.borrow(), |s| s.as_ref().unwrap()))
}
+ /// Gets the current version of the registry index.
+ ///
+ /// It is usually sha of the HEAD commit from the underlying Git repository.
fn current_version(&self) -> Option<InternedString> {
if let Some(sha) = self.current_sha.get() {
return Some(sha);
@@ -143,20 +190,24 @@ impl<'cfg> RemoteRegistry<'cfg> {
Some(sha)
}
+ /// Whether the registry is up-to-date. See [`Self::mark_updated`] for more.
fn is_updated(&self) -> bool {
self.config.updated_sources().contains(&self.source_id)
}
+ /// Marks this registry as up-to-date.
+ ///
+ /// This makes sure the index is only updated once per session since it is
+ /// an expensive operation. This generally only happens when the resolver
+ /// is run multiple times, such as during `cargo publish`.
fn mark_updated(&self) {
self.config.updated_sources().insert(self.source_id);
}
}
-const LAST_UPDATED_FILE: &str = ".last-updated";
-
impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
fn prepare(&self) -> CargoResult<()> {
- self.repo()?; // create intermediate dirs and initialize the repo
+ self.repo()?;
Ok(())
}
@@ -168,13 +219,20 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
self.config.assert_package_cache_locked(path)
}
- // `index_version` Is a string representing the version of the file used to construct the cached copy.
- // Older versions of Cargo used the single value of the hash of the HEAD commit as a `index_version`.
- // This is technically correct but a little too conservative. If a new commit is fetched all cached
- // files need to be regenerated even if a particular file was not changed.
- // However if an old cargo has written such a file we still know how to read it, as long as we check for that hash value.
- //
- // Cargo now uses a hash of the file's contents as provided by git.
+ /// Read the general concept for `load()` on [`RegistryData::load`].
+ ///
+ /// `index_version` is a string representing the version of the file used
+ /// to construct the cached copy.
+ ///
+ /// Older versions of Cargo used the single value of the hash of the HEAD
+ /// commit as a `index_version`. This is technically correct but a little
+ /// too conservative. If a new commit is fetched all cached files need to
+ /// be regenerated even if a particular file was not changed.
+ ///
+ /// However if an old cargo has written such a file we still know how to
+ /// read it, as long as we check for that hash value.
+ ///
+ /// Cargo now uses a hash of the file's contents as provided by git.
fn load(
&mut self,
_root: &Path,
@@ -187,7 +245,8 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
// Check if the cache is valid.
let git_commit_hash = self.current_version();
if index_version.is_some() && index_version == git_commit_hash.as_deref() {
- // This file was written by an old version of cargo, but it is still up-to-date.
+ // This file was written by an old version of cargo, but it is
+ // still up-to-date.
return Poll::Ready(Ok(LoadResponse::CacheValid));
}
// Note that the index calls this method and the filesystem is locked
@@ -224,8 +283,8 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
match load_helper(&self, path, index_version) {
Ok(result) => Poll::Ready(Ok(result)),
Err(_) if !self.is_updated() => {
- // If git returns an error and we haven't updated the repo, return
- // pending to allow an update to try again.
+ // If git returns an error and we haven't updated the repo,
+ // return pending to allow an update to try again.
self.needs_update = true;
Poll::Pending
}
@@ -245,7 +304,7 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
debug!("loading config");
self.prepare()?;
self.config.assert_package_cache_locked(&self.index_path);
- match ready!(self.load(Path::new(""), Path::new("config.json"), None)?) {
+ match ready!(self.load(Path::new(""), Path::new(RegistryConfig::NAME), None)?) {
LoadResponse::Data { raw_data, .. } => {
trace!("config loaded");
let mut cfg: RegistryConfig = serde_json::from_slice(&raw_data)?;
@@ -265,9 +324,6 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
self.needs_update = false;
- // Make sure the index is only updated once per session since it is an
- // expensive operation. This generally only happens when the resolver
- // is run multiple times, such as during `cargo publish`.
if self.is_updated() {
return Ok(());
}
@@ -294,7 +350,7 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
self.head.set(None);
*self.tree.borrow_mut() = None;
self.current_sha.set(None);
- let path = self.config.assert_package_cache_locked(&self.index_path);
+ let _path = self.config.assert_package_cache_locked(&self.index_path);
if !self.quiet {
self.config
.shell()
@@ -314,15 +370,14 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
)
.with_context(|| format!("failed to fetch `{}`", url))?;
- // Create a dummy file to record the mtime for when we updated the
- // index.
- paths::create(&path.join(LAST_UPDATED_FILE))?;
-
Ok(())
}
+ /// Read the general concept for `invalidate_cache()` on
+ /// [`RegistryData::invalidate_cache`].
+ ///
+ /// To fully invalidate, undo [`RemoteRegistry::mark_updated`]'s work.
fn invalidate_cache(&mut self) {
- // To fully invalidate, undo `mark_updated`s work
self.needs_update = true;
}
@@ -365,9 +420,10 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
}
}
+/// Implemented to just be sure to drop `tree` field before our other fields.
+/// See SAFETY inside [`RemoteRegistry::tree()`] for more.
impl<'cfg> Drop for RemoteRegistry<'cfg> {
fn drop(&mut self) {
- // Just be sure to drop this before our other fields
self.tree.borrow_mut().take();
}
}
diff --git a/src/tools/cargo/src/cargo/util/auth/asymmetric.rs b/src/tools/cargo/src/cargo/util/auth/asymmetric.rs
new file mode 100644
index 000000000..50882a745
--- /dev/null
+++ b/src/tools/cargo/src/cargo/util/auth/asymmetric.rs
@@ -0,0 +1,155 @@
+//! Registry asymmetric authentication support. See [RFC 3231] for more.
+//!
+//! [RFC 3231]: https://rust-lang.github.io/rfcs/3231-cargo-asymmetric-tokens.html
+
+use pasetors::keys::AsymmetricPublicKey;
+use pasetors::keys::AsymmetricSecretKey;
+use pasetors::paserk;
+use pasetors::paserk::FormatAsPaserk;
+use pasetors::version3;
+use pasetors::version3::PublicToken;
+use time::format_description::well_known::Rfc3339;
+use time::OffsetDateTime;
+
+use crate::core::SourceId;
+use crate::ops::RegistryCredentialConfig;
+use crate::CargoResult;
+
+use super::Mutation;
+use super::Secret;
+
+/// The main body of an asymmetric token as describe in RFC 3231.
+#[derive(serde::Serialize)]
+struct Message<'a> {
+ iat: &'a str,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ sub: Option<&'a str>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ mutation: Option<&'a str>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ name: Option<&'a str>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ vers: Option<&'a str>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ cksum: Option<&'a str>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ challenge: Option<&'a str>,
+ /// This field is not yet used. This field can be set to a value >1 to
+ /// indicate a breaking change in the token format.
+ #[serde(skip_serializing_if = "Option::is_none")]
+ v: Option<u8>,
+}
+
+/// The footer of an asymmetric token as describe in RFC 3231.
+#[derive(serde::Serialize)]
+struct Footer<'a> {
+ url: &'a str,
+ kip: paserk::Id,
+}
+
+/// Checks that a secret key is valid, and returns the associated public key in
+/// Paserk format.
+pub fn paserk_public_from_paserk_secret(secret_key: Secret<&str>) -> Option<String> {
+ let secret: Secret<AsymmetricSecretKey<version3::V3>> =
+ secret_key.map(|key| key.try_into()).transpose().ok()?;
+ let public: AsymmetricPublicKey<version3::V3> = secret
+ .as_ref()
+ .map(|key| key.try_into())
+ .transpose()
+ .ok()?
+ .expose();
+ let mut paserk_pub_key = String::new();
+ FormatAsPaserk::fmt(&public, &mut paserk_pub_key).unwrap();
+ Some(paserk_pub_key)
+}
+
+/// Generates a public token from a registry's `credential` configuration for
+/// authenticating to a `source_id`
+///
+/// An optional `mutation` for authenticating a mutation operation aganist the
+/// registry.
+pub fn public_token_from_credential(
+ credential: RegistryCredentialConfig,
+ source_id: &SourceId,
+ mutation: Option<&'_ Mutation<'_>>,
+) -> CargoResult<Secret<String>> {
+ let RegistryCredentialConfig::AsymmetricKey((secret_key, secret_key_subject)) = credential else {
+ anyhow::bail!("credential must be an asymmetric secret key")
+ };
+
+ let secret: Secret<AsymmetricSecretKey<version3::V3>> =
+ secret_key.map(|key| key.as_str().try_into()).transpose()?;
+ let public: AsymmetricPublicKey<version3::V3> = secret
+ .as_ref()
+ .map(|key| key.try_into())
+ .transpose()?
+ .expose();
+ let kip = (&public).try_into()?;
+ let iat = OffsetDateTime::now_utc();
+
+ let message = Message {
+ iat: &iat.format(&Rfc3339)?,
+ sub: secret_key_subject.as_deref(),
+ mutation: mutation.and_then(|m| {
+ Some(match m {
+ Mutation::PrePublish => return None,
+ Mutation::Publish { .. } => "publish",
+ Mutation::Yank { .. } => "yank",
+ Mutation::Unyank { .. } => "unyank",
+ Mutation::Owners { .. } => "owners",
+ })
+ }),
+ name: mutation.and_then(|m| {
+ Some(match m {
+ Mutation::PrePublish => return None,
+ Mutation::Publish { name, .. }
+ | Mutation::Yank { name, .. }
+ | Mutation::Unyank { name, .. }
+ | Mutation::Owners { name, .. } => *name,
+ })
+ }),
+ vers: mutation.and_then(|m| {
+ Some(match m {
+ Mutation::PrePublish | Mutation::Owners { .. } => return None,
+ Mutation::Publish { vers, .. }
+ | Mutation::Yank { vers, .. }
+ | Mutation::Unyank { vers, .. } => *vers,
+ })
+ }),
+ cksum: mutation.and_then(|m| {
+ Some(match m {
+ Mutation::PrePublish
+ | Mutation::Yank { .. }
+ | Mutation::Unyank { .. }
+ | Mutation::Owners { .. } => return None,
+ Mutation::Publish { cksum, .. } => *cksum,
+ })
+ }),
+ challenge: None, // todo: PASETO with challenges
+ v: None,
+ };
+
+ let footer = Footer {
+ url: &source_id.url().to_string(),
+ kip,
+ };
+
+ let secret = secret
+ .map(|secret| {
+ PublicToken::sign(
+ &secret,
+ serde_json::to_string(&message)
+ .expect("cannot serialize")
+ .as_bytes(),
+ Some(
+ serde_json::to_string(&footer)
+ .expect("cannot serialize")
+ .as_bytes(),
+ ),
+ None,
+ )
+ })
+ .transpose()?;
+
+ Ok(secret)
+}
diff --git a/src/tools/cargo/src/cargo/util/auth.rs b/src/tools/cargo/src/cargo/util/auth/mod.rs
index f19acaebe..58309964f 100644
--- a/src/tools/cargo/src/cargo/util/auth.rs
+++ b/src/tools/cargo/src/cargo/util/auth/mod.rs
@@ -1,11 +1,11 @@
//! Registry authentication support.
+mod asymmetric;
+
use crate::util::{config, config::ConfigKey, CanonicalUrl, CargoResult, Config, IntoUrl};
use anyhow::{bail, format_err, Context as _};
use cargo_util::ProcessError;
use core::fmt;
-use pasetors::keys::{AsymmetricPublicKey, AsymmetricSecretKey};
-use pasetors::paserk::FormatAsPaserk;
use serde::Deserialize;
use std::collections::HashMap;
use std::error::Error;
@@ -13,13 +13,13 @@ use std::io::{Read, Write};
use std::ops::Deref;
use std::path::PathBuf;
use std::process::{Command, Stdio};
-use time::format_description::well_known::Rfc3339;
-use time::OffsetDateTime;
use url::Url;
use crate::core::SourceId;
use crate::ops::RegistryCredentialConfig;
+pub use self::asymmetric::paserk_public_from_paserk_secret;
+
use super::config::CredentialCacheValue;
/// A wrapper for values that should not be printed.
@@ -466,82 +466,9 @@ fn auth_token_optional(
run_command(config, &process, sid, Action::Get)?.unwrap();
(independent_of_endpoint, Secret::from(token))
}
- RegistryCredentialConfig::AsymmetricKey((secret_key, secret_key_subject)) => {
- let secret: Secret<AsymmetricSecretKey<pasetors::version3::V3>> =
- secret_key.map(|key| key.as_str().try_into()).transpose()?;
- let public: AsymmetricPublicKey<pasetors::version3::V3> = secret
- .as_ref()
- .map(|key| key.try_into())
- .transpose()?
- .expose();
- let kip: pasetors::paserk::Id = (&public).try_into()?;
- let iat = OffsetDateTime::now_utc();
-
- let message = Message {
- iat: &iat.format(&Rfc3339)?,
- sub: secret_key_subject.as_deref(),
- mutation: mutation.and_then(|m| {
- Some(match m {
- Mutation::PrePublish => return None,
- Mutation::Publish { .. } => "publish",
- Mutation::Yank { .. } => "yank",
- Mutation::Unyank { .. } => "unyank",
- Mutation::Owners { .. } => "owners",
- })
- }),
- name: mutation.and_then(|m| {
- Some(match m {
- Mutation::PrePublish => return None,
- Mutation::Publish { name, .. }
- | Mutation::Yank { name, .. }
- | Mutation::Unyank { name, .. }
- | Mutation::Owners { name, .. } => *name,
- })
- }),
- vers: mutation.and_then(|m| {
- Some(match m {
- Mutation::PrePublish | Mutation::Owners { .. } => return None,
- Mutation::Publish { vers, .. }
- | Mutation::Yank { vers, .. }
- | Mutation::Unyank { vers, .. } => *vers,
- })
- }),
- cksum: mutation.and_then(|m| {
- Some(match m {
- Mutation::PrePublish
- | Mutation::Yank { .. }
- | Mutation::Unyank { .. }
- | Mutation::Owners { .. } => return None,
- Mutation::Publish { cksum, .. } => *cksum,
- })
- }),
- challenge: None, // todo: PASETO with challenges
- v: None,
- };
- let footer = Footer {
- url: &sid.url().to_string(),
- kip,
- };
-
- (
- false,
- secret
- .map(|secret| {
- pasetors::version3::PublicToken::sign(
- &secret,
- serde_json::to_string(&message)
- .expect("cannot serialize")
- .as_bytes(),
- Some(
- serde_json::to_string(&footer)
- .expect("cannot serialize")
- .as_bytes(),
- ),
- None,
- )
- })
- .transpose()?,
- )
+ cred @ RegistryCredentialConfig::AsymmetricKey(..) => {
+ let token = asymmetric::public_token_from_credential(cred, sid, mutation)?;
+ (false, token)
}
};
@@ -595,33 +522,6 @@ pub enum Mutation<'a> {
},
}
-/// The main body of an asymmetric token as describe in RFC 3231.
-#[derive(serde::Serialize)]
-struct Message<'a> {
- iat: &'a str,
- #[serde(skip_serializing_if = "Option::is_none")]
- sub: Option<&'a str>,
- #[serde(skip_serializing_if = "Option::is_none")]
- mutation: Option<&'a str>,
- #[serde(skip_serializing_if = "Option::is_none")]
- name: Option<&'a str>,
- #[serde(skip_serializing_if = "Option::is_none")]
- vers: Option<&'a str>,
- #[serde(skip_serializing_if = "Option::is_none")]
- cksum: Option<&'a str>,
- #[serde(skip_serializing_if = "Option::is_none")]
- challenge: Option<&'a str>,
- /// This field is not yet used. This field can be set to a value >1 to indicate a breaking change in the token format.
- #[serde(skip_serializing_if = "Option::is_none")]
- v: Option<u8>,
-}
-/// The footer of an asymmetric token as describe in RFC 3231.
-#[derive(serde::Serialize)]
-struct Footer<'a> {
- url: &'a str,
- kip: pasetors::paserk::Id,
-}
-
enum Action {
Get,
Store(String),
@@ -646,21 +546,6 @@ pub fn login(config: &Config, sid: &SourceId, token: RegistryCredentialConfig) -
Ok(())
}
-/// Checks that a secret key is valid, and returns the associated public key in Paserk format.
-pub(crate) fn paserk_public_from_paserk_secret(secret_key: Secret<&str>) -> Option<String> {
- let secret: Secret<AsymmetricSecretKey<pasetors::version3::V3>> =
- secret_key.map(|key| key.try_into()).transpose().ok()?;
- let public: AsymmetricPublicKey<pasetors::version3::V3> = secret
- .as_ref()
- .map(|key| key.try_into())
- .transpose()
- .ok()?
- .expose();
- let mut paserk_pub_key = String::new();
- FormatAsPaserk::fmt(&public, &mut paserk_pub_key).unwrap();
- Some(paserk_pub_key)
-}
-
/// Removes the token for the given registry.
pub fn logout(config: &Config, sid: &SourceId) -> CargoResult<()> {
match registry_credential_config(config, sid)? {
diff --git a/src/tools/cargo/src/cargo/util/command_prelude.rs b/src/tools/cargo/src/cargo/util/command_prelude.rs
index c18785c66..46ed7dd7c 100644
--- a/src/tools/cargo/src/cargo/util/command_prelude.rs
+++ b/src/tools/cargo/src/cargo/util/command_prelude.rs
@@ -15,6 +15,7 @@ use crate::CargoResult;
use anyhow::bail;
use cargo_util::paths;
use std::ffi::{OsStr, OsString};
+use std::path::Path;
use std::path::PathBuf;
pub use crate::core::compiler::CompileMode;
@@ -23,6 +24,8 @@ pub use clap::{value_parser, Arg, ArgAction, ArgMatches};
pub use clap::Command;
+use super::config::JobsConfig;
+
pub trait CommandExt: Sized {
fn _arg(self, arg: Arg) -> Self;
@@ -66,7 +69,7 @@ pub trait CommandExt: Sized {
fn arg_jobs(self) -> Self {
self._arg(
- opt("jobs", "Number of parallel jobs, defaults to # of CPUs")
+ opt("jobs", "Number of parallel jobs, defaults to # of CPUs.")
.short('j')
.value_name("N")
.allow_hyphen_values(true),
@@ -337,22 +340,7 @@ pub trait ArgMatchesExt {
}
fn root_manifest(&self, config: &Config) -> CargoResult<PathBuf> {
- if let Some(path) = self.value_of_path("manifest-path", config) {
- // In general, we try to avoid normalizing paths in Cargo,
- // but in this particular case we need it to fix #3586.
- let path = paths::normalize_path(&path);
- if !path.ends_with("Cargo.toml") {
- anyhow::bail!("the manifest-path must be a path to a Cargo.toml file")
- }
- if !path.exists() {
- anyhow::bail!(
- "manifest path `{}` does not exist",
- self._value_of("manifest-path").unwrap()
- )
- }
- return Ok(path);
- }
- find_root_manifest_for_wd(config.cwd())
+ root_manifest(self._value_of("manifest-path").map(Path::new), config)
}
fn workspace<'a>(&self, config: &'a Config) -> CargoResult<Workspace<'a>> {
@@ -364,8 +352,16 @@ pub trait ArgMatchesExt {
Ok(ws)
}
- fn jobs(&self) -> CargoResult<Option<i32>> {
- self.value_of_i32("jobs")
+ fn jobs(&self) -> CargoResult<Option<JobsConfig>> {
+ let arg = match self._value_of("jobs") {
+ None => None,
+ Some(arg) => match arg.parse::<i32>() {
+ Ok(j) => Some(JobsConfig::Integer(j)),
+ Err(_) => Some(JobsConfig::String(arg.to_string())),
+ },
+ };
+
+ Ok(arg)
}
fn verbose(&self) -> u32 {
@@ -782,6 +778,33 @@ pub fn values_os(args: &ArgMatches, name: &str) -> Vec<OsString> {
args._values_of_os(name)
}
+pub fn root_manifest(manifest_path: Option<&Path>, config: &Config) -> CargoResult<PathBuf> {
+ if let Some(manifest_path) = manifest_path {
+ let path = config.cwd().join(manifest_path);
+ // In general, we try to avoid normalizing paths in Cargo,
+ // but in this particular case we need it to fix #3586.
+ let path = paths::normalize_path(&path);
+ if !path.ends_with("Cargo.toml") && !crate::util::toml::is_embedded(&path) {
+ anyhow::bail!("the manifest-path must be a path to a Cargo.toml file")
+ }
+ if !path.exists() {
+ anyhow::bail!("manifest path `{}` does not exist", manifest_path.display())
+ }
+ if path.is_dir() {
+ anyhow::bail!(
+ "manifest path `{}` is a directory but expected a file",
+ manifest_path.display()
+ )
+ }
+ if crate::util::toml::is_embedded(&path) && !config.cli_unstable().script {
+ anyhow::bail!("embedded manifest `{}` requires `-Zscript`", path.display())
+ }
+ Ok(path)
+ } else {
+ find_root_manifest_for_wd(config.cwd())
+ }
+}
+
#[track_caller]
pub fn ignore_unknown<T: Default>(r: Result<T, clap::parser::MatchesError>) -> T {
match r {
diff --git a/src/tools/cargo/src/cargo/util/config/mod.rs b/src/tools/cargo/src/cargo/util/config/mod.rs
index 076b78299..4e6bca302 100644
--- a/src/tools/cargo/src/cargo/util/config/mod.rs
+++ b/src/tools/cargo/src/cargo/util/config/mod.rs
@@ -69,9 +69,11 @@ use self::ConfigValue as CV;
use crate::core::compiler::rustdoc::RustdocExternMap;
use crate::core::shell::Verbosity;
use crate::core::{features, CliUnstable, Shell, SourceId, Workspace, WorkspaceRootConfig};
-use crate::ops::{self, RegistryCredentialConfig};
+use crate::ops::RegistryCredentialConfig;
use crate::util::auth::Secret;
use crate::util::errors::CargoResult;
+use crate::util::network::http::configure_http_handle;
+use crate::util::network::http::http_handle;
use crate::util::CanonicalUrl;
use crate::util::{internal, toml as cargo_toml};
use crate::util::{try_canonicalize, validate_package_name};
@@ -363,7 +365,7 @@ impl Config {
self.registry_base_path().join("index")
}
- /// Gets the Cargo registry cache directory (`<cargo_home>/registry/path`).
+ /// Gets the Cargo registry cache directory (`<cargo_home>/registry/cache`).
pub fn registry_cache_path(&self) -> Filesystem {
self.registry_base_path().join("cache")
}
@@ -1273,6 +1275,16 @@ impl Config {
return Ok(Vec::new());
}
};
+
+ for (path, abs_path, def) in &includes {
+ if abs_path.extension() != Some(OsStr::new("toml")) {
+ bail!(
+ "expected a config include path ending with `.toml`, \
+ but found `{path}` from `{def}`",
+ )
+ }
+ }
+
Ok(includes)
}
@@ -1706,11 +1718,11 @@ impl Config {
pub fn http(&self) -> CargoResult<&RefCell<Easy>> {
let http = self
.easy
- .try_borrow_with(|| ops::http_handle(self).map(RefCell::new))?;
+ .try_borrow_with(|| http_handle(self).map(RefCell::new))?;
{
let mut http = http.borrow_mut();
http.reset();
- let timeout = ops::configure_http_handle(self, &mut http)?;
+ let timeout = configure_http_handle(self, &mut http)?;
timeout.configure(&mut http)?;
}
Ok(http)
@@ -2453,6 +2465,25 @@ pub struct CargoSshConfig {
pub known_hosts: Option<Vec<Value<String>>>,
}
+/// Configuration for `jobs` in `build` section. There are two
+/// ways to configure: An integer or a simple string expression.
+///
+/// ```toml
+/// [build]
+/// jobs = 1
+/// ```
+///
+/// ```toml
+/// [build]
+/// jobs = "default" # Currently only support "default".
+/// ```
+#[derive(Debug, Deserialize, Clone)]
+#[serde(untagged)]
+pub enum JobsConfig {
+ Integer(i32),
+ String(String),
+}
+
#[derive(Debug, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct CargoBuildConfig {
@@ -2462,7 +2493,7 @@ pub struct CargoBuildConfig {
pub target_dir: Option<ConfigRelativePath>,
pub incremental: Option<bool>,
pub target: Option<BuildTargetConfig>,
- pub jobs: Option<i32>,
+ pub jobs: Option<JobsConfig>,
pub rustflags: Option<StringList>,
pub rustdocflags: Option<StringList>,
pub rustc_wrapper: Option<ConfigRelativePath>,
diff --git a/src/tools/cargo/src/cargo/util/config/target.rs b/src/tools/cargo/src/cargo/util/config/target.rs
index a7f2f3ef2..cdafe73dd 100644
--- a/src/tools/cargo/src/cargo/util/config/target.rs
+++ b/src/tools/cargo/src/cargo/util/config/target.rs
@@ -1,5 +1,5 @@
use super::{Config, ConfigKey, ConfigRelativePath, OptValue, PathAndArgs, StringList, CV};
-use crate::core::compiler::{BuildOutput, LinkType};
+use crate::core::compiler::{BuildOutput, LinkArgTarget};
use crate::util::CargoResult;
use serde::Deserialize;
use std::collections::{BTreeMap, HashMap};
@@ -178,27 +178,27 @@ fn parse_links_overrides(
.extend(list.iter().map(|v| PathBuf::from(&v.0)));
}
"rustc-link-arg-cdylib" | "rustc-cdylib-link-arg" => {
- let args = extra_link_args(LinkType::Cdylib, key, value)?;
+ let args = extra_link_args(LinkArgTarget::Cdylib, key, value)?;
output.linker_args.extend(args);
}
"rustc-link-arg-bins" => {
- let args = extra_link_args(LinkType::Bin, key, value)?;
+ let args = extra_link_args(LinkArgTarget::Bin, key, value)?;
output.linker_args.extend(args);
}
"rustc-link-arg" => {
- let args = extra_link_args(LinkType::All, key, value)?;
+ let args = extra_link_args(LinkArgTarget::All, key, value)?;
output.linker_args.extend(args);
}
"rustc-link-arg-tests" => {
- let args = extra_link_args(LinkType::Test, key, value)?;
+ let args = extra_link_args(LinkArgTarget::Test, key, value)?;
output.linker_args.extend(args);
}
"rustc-link-arg-benches" => {
- let args = extra_link_args(LinkType::Bench, key, value)?;
+ let args = extra_link_args(LinkArgTarget::Bench, key, value)?;
output.linker_args.extend(args);
}
"rustc-link-arg-examples" => {
- let args = extra_link_args(LinkType::Example, key, value)?;
+ let args = extra_link_args(LinkArgTarget::Example, key, value)?;
output.linker_args.extend(args);
}
"rustc-cfg" => {
@@ -237,10 +237,10 @@ fn parse_links_overrides(
}
fn extra_link_args<'a>(
- link_type: LinkType,
+ link_type: LinkArgTarget,
key: &str,
value: &'a CV,
-) -> CargoResult<impl Iterator<Item = (LinkType, String)> + 'a> {
+) -> CargoResult<impl Iterator<Item = (LinkArgTarget, String)> + 'a> {
let args = value.list(key)?;
Ok(args.iter().map(move |v| (link_type.clone(), v.0.clone())))
}
diff --git a/src/tools/cargo/src/cargo/util/interning.rs b/src/tools/cargo/src/cargo/util/interning.rs
index bbec12942..584fdf623 100644
--- a/src/tools/cargo/src/cargo/util/interning.rs
+++ b/src/tools/cargo/src/cargo/util/interning.rs
@@ -10,14 +10,13 @@ use std::path::Path;
use std::ptr;
use std::str;
use std::sync::Mutex;
+use std::sync::OnceLock;
fn leak(s: String) -> &'static str {
Box::leak(s.into_boxed_str())
}
-lazy_static::lazy_static! {
- static ref STRING_CACHE: Mutex<HashSet<&'static str>> = Mutex::new(HashSet::new());
-}
+static STRING_CACHE: OnceLock<Mutex<HashSet<&'static str>>> = OnceLock::new();
#[derive(Clone, Copy)]
pub struct InternedString {
@@ -64,7 +63,10 @@ impl Eq for InternedString {}
impl InternedString {
pub fn new(str: &str) -> InternedString {
- let mut cache = STRING_CACHE.lock().unwrap();
+ let mut cache = STRING_CACHE
+ .get_or_init(|| Default::default())
+ .lock()
+ .unwrap();
let s = cache.get(str).cloned().unwrap_or_else(|| {
let s = leak(str.to_string());
cache.insert(s);
diff --git a/src/tools/cargo/src/cargo/util/network/http.rs b/src/tools/cargo/src/cargo/util/network/http.rs
new file mode 100644
index 000000000..f077ce2b6
--- /dev/null
+++ b/src/tools/cargo/src/cargo/util/network/http.rs
@@ -0,0 +1,216 @@
+//! Configures libcurl's http handles.
+
+use std::str;
+use std::time::Duration;
+
+use anyhow::bail;
+use curl::easy::Easy;
+use curl::easy::InfoType;
+use curl::easy::SslOpt;
+use curl::easy::SslVersion;
+use log::log;
+use log::Level;
+
+use crate::util::config::SslVersionConfig;
+use crate::util::config::SslVersionConfigRange;
+use crate::version;
+use crate::CargoResult;
+use crate::Config;
+
+/// Creates a new HTTP handle with appropriate global configuration for cargo.
+pub fn http_handle(config: &Config) -> CargoResult<Easy> {
+ let (mut handle, timeout) = http_handle_and_timeout(config)?;
+ timeout.configure(&mut handle)?;
+ Ok(handle)
+}
+
+pub fn http_handle_and_timeout(config: &Config) -> CargoResult<(Easy, HttpTimeout)> {
+ if config.frozen() {
+ bail!(
+ "attempting to make an HTTP request, but --frozen was \
+ specified"
+ )
+ }
+ if config.offline() {
+ bail!(
+ "attempting to make an HTTP request, but --offline was \
+ specified"
+ )
+ }
+
+ // The timeout option for libcurl by default times out the entire transfer,
+ // but we probably don't want this. Instead we only set timeouts for the
+ // connect phase as well as a "low speed" timeout so if we don't receive
+ // many bytes in a large-ish period of time then we time out.
+ let mut handle = Easy::new();
+ let timeout = configure_http_handle(config, &mut handle)?;
+ 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(
+ super::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) = super::proxy::http_proxy(http) {
+ handle.proxy(&proxy)?;
+ }
+ if let Some(cainfo) = &http.cainfo {
+ let cainfo = cainfo.resolve_path(config);
+ handle.cainfo(&cainfo)?;
+ }
+ if let Some(check) = http.check_revoke {
+ handle.ssl_options(SslOpt::new().no_revoke(!check))?;
+ }
+
+ if let Some(user_agent) = &http.user_agent {
+ handle.useragent(user_agent)?;
+ } else {
+ handle.useragent(&format!("cargo {}", version()))?;
+ }
+
+ fn to_ssl_version(s: &str) -> CargoResult<SslVersion> {
+ let version = match s {
+ "default" => SslVersion::Default,
+ "tlsv1" => SslVersion::Tlsv1,
+ "tlsv1.0" => SslVersion::Tlsv10,
+ "tlsv1.1" => SslVersion::Tlsv11,
+ "tlsv1.2" => SslVersion::Tlsv12,
+ "tlsv1.3" => SslVersion::Tlsv13,
+ _ => bail!(
+ "Invalid ssl version `{s}`,\
+ choose from 'default', 'tlsv1', 'tlsv1.0', 'tlsv1.1', 'tlsv1.2', 'tlsv1.3'."
+ ),
+ };
+ Ok(version)
+ }
+
+ // Empty string accept encoding expands to the encodings supported by the current libcurl.
+ handle.accept_encoding("")?;
+ if let Some(ssl_version) = &http.ssl_version {
+ match ssl_version {
+ SslVersionConfig::Single(s) => {
+ let version = to_ssl_version(s.as_str())?;
+ handle.ssl_version(version)?;
+ }
+ SslVersionConfig::Range(SslVersionConfigRange { min, max }) => {
+ let min_version = min
+ .as_ref()
+ .map_or(Ok(SslVersion::Default), |s| to_ssl_version(s))?;
+ let max_version = max
+ .as_ref()
+ .map_or(Ok(SslVersion::Default), |s| to_ssl_version(s))?;
+ handle.ssl_min_max_version(min_version, max_version)?;
+ }
+ }
+ } else if cfg!(windows) {
+ // This is a temporary workaround for some bugs with libcurl and
+ // schannel and TLS 1.3.
+ //
+ // Our libcurl on Windows is usually built with schannel.
+ // On Windows 11 (or Windows Server 2022), libcurl recently (late
+ // 2022) gained support for TLS 1.3 with schannel, and it now defaults
+ // to 1.3. Unfortunately there have been some bugs with this.
+ // https://github.com/curl/curl/issues/9431 is the most recent. Once
+ // that has been fixed, and some time has passed where we can be more
+ // confident that the 1.3 support won't cause issues, this can be
+ // removed.
+ //
+ // Windows 10 is unaffected. libcurl does not support TLS 1.3 on
+ // Windows 10. (Windows 10 sorta had support, but it required enabling
+ // an advanced option in the registry which was buggy, and libcurl
+ // does runtime checks to prevent it.)
+ handle.ssl_min_max_version(SslVersion::Default, SslVersion::Tlsv12)?;
+ }
+
+ if let Some(true) = http.debug {
+ handle.verbose(true)?;
+ log::debug!("{:#?}", curl::Version::get());
+ handle.debug_function(|kind, data| {
+ let (prefix, level) = match kind {
+ InfoType::Text => ("*", Level::Debug),
+ InfoType::HeaderIn => ("<", Level::Debug),
+ InfoType::HeaderOut => (">", Level::Debug),
+ InfoType::DataIn => ("{", Level::Trace),
+ InfoType::DataOut => ("}", Level::Trace),
+ 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 starts_with_ignore_case(line, "authorization:") {
+ line = "Authorization: [REDACTED]";
+ } 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);
+ }
+ }
+ Err(_) => {
+ log!(
+ level,
+ "http-debug: {} ({} bytes of data)",
+ prefix,
+ data.len()
+ );
+ }
+ }
+ })?;
+ }
+
+ HttpTimeout::new(config)
+}
+
+#[must_use]
+pub struct HttpTimeout {
+ pub dur: Duration,
+ pub low_speed_limit: u32,
+}
+
+impl HttpTimeout {
+ pub fn new(config: &Config) -> CargoResult<HttpTimeout> {
+ let http_config = config.http_config()?;
+ let low_speed_limit = http_config.low_speed_limit.unwrap_or(10);
+ let seconds = http_config
+ .timeout
+ .or_else(|| {
+ config
+ .get_env("HTTP_TIMEOUT")
+ .ok()
+ .and_then(|s| s.parse().ok())
+ })
+ .unwrap_or(30);
+ Ok(HttpTimeout {
+ dur: Duration::new(seconds, 0),
+ low_speed_limit,
+ })
+ }
+
+ pub fn configure(&self, handle: &mut Easy) -> CargoResult<()> {
+ // The timeout option for libcurl by default times out the entire
+ // transfer, but we probably don't want this. Instead we only set
+ // timeouts for the connect phase as well as a "low speed" timeout so
+ // if we don't receive many bytes in a large-ish period of time then we
+ // time out.
+ handle.connect_timeout(self.dur)?;
+ handle.low_speed_time(self.dur)?;
+ handle.low_speed_limit(self.low_speed_limit)?;
+ Ok(())
+ }
+}
diff --git a/src/tools/cargo/src/cargo/util/network/mod.rs b/src/tools/cargo/src/cargo/util/network/mod.rs
index 2006bb65f..b078fa352 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 http;
pub mod proxy;
pub mod retry;
pub mod sleep;
@@ -20,20 +21,51 @@ impl<T> PollExt<T> for Poll<T> {
}
}
-// When dynamically linked against libcurl, we want to ignore some failures
-// when using old versions that don't support certain features.
+/// When dynamically linked against libcurl, we want to ignore some failures
+/// when using old versions that don't support certain features.
#[macro_export]
macro_rules! try_old_curl {
($e:expr, $msg:expr) => {
let result = $e;
if cfg!(target_os = "macos") {
if let Err(e) = result {
- warn!("ignoring libcurl {} error: {}", $msg, e);
+ ::log::warn!("ignoring libcurl {} error: {}", $msg, e);
}
} else {
+ use ::anyhow::Context;
result.with_context(|| {
- anyhow::format_err!("failed to enable {}, is curl not built right?", $msg)
+ ::anyhow::format_err!("failed to enable {}, is curl not built right?", $msg)
})?;
}
};
}
+
+/// Enable HTTP/2 and pipewait to be used as it'll allow true multiplexing
+/// which makes downloads much faster.
+///
+/// Currently Cargo requests the `http2` feature of the `curl` crate which
+/// means it should always be built in. On OSX, however, we ship cargo still
+/// linked against the system libcurl. Building curl with ALPN support for
+/// HTTP/2 requires newer versions of OSX (the SecureTransport API) than we
+/// want to ship Cargo for. By linking Cargo against the system libcurl then
+/// older curl installations won't use HTTP/2 but newer ones will. All that to
+/// basically say we ignore errors here on OSX, but consider this a fatal error
+/// to not activate HTTP/2 on all other platforms.
+///
+/// `pipewait` is an option which indicates that if there's a bunch of parallel
+/// requests to the same host they all wait until the pipelining status of the
+/// host is known. This means that we won't initiate dozens of connections but
+/// rather only one. Once the main one is opened we realized that pipelining is
+/// possible and multiplexing is possible. All in all this reduces the number
+/// of connections down to a more manageable state.
+#[macro_export]
+macro_rules! try_old_curl_http2_pipewait {
+ ($multiplexing:expr, $handle:expr) => {
+ if $multiplexing {
+ $crate::try_old_curl!($handle.http_version(curl::easy::HttpVersion::V2), "HTTP/2");
+ } else {
+ $handle.http_version(curl::easy::HttpVersion::V11)?;
+ }
+ $crate::try_old_curl!($handle.pipewait(true), "pipewait");
+ };
+}
diff --git a/src/tools/cargo/src/cargo/util/network/retry.rs b/src/tools/cargo/src/cargo/util/network/retry.rs
index 42c38ab9f..5cb7d1e4f 100644
--- a/src/tools/cargo/src/cargo/util/network/retry.rs
+++ b/src/tools/cargo/src/cargo/util/network/retry.rs
@@ -56,21 +56,29 @@ impl<'a> Retry<'a> {
return RetryResult::Err(e);
}
self.retries += 1;
- let sleep = if self.retries == 1 {
- let mut rng = rand::thread_rng();
- INITIAL_RETRY_SLEEP_BASE_MS + rng.gen_range(0..INITIAL_RETRY_JITTER_MS)
- } else {
- min(
- ((self.retries - 1) * 3) * 1000 + INITIAL_RETRY_SLEEP_BASE_MS,
- MAX_RETRY_SLEEP_MS,
- )
- };
- RetryResult::Retry(sleep)
+ RetryResult::Retry(self.next_sleep_ms())
}
Err(e) => RetryResult::Err(e),
Ok(r) => RetryResult::Success(r),
}
}
+
+ /// Gets the next sleep duration in milliseconds.
+ fn next_sleep_ms(&self) -> u64 {
+ if let Ok(sleep) = self.config.get_env("__CARGO_TEST_FIXED_RETRY_SLEEP_MS") {
+ return sleep.parse().expect("a u64");
+ }
+
+ if self.retries == 1 {
+ let mut rng = rand::thread_rng();
+ INITIAL_RETRY_SLEEP_BASE_MS + rng.gen_range(0..INITIAL_RETRY_JITTER_MS)
+ } else {
+ min(
+ ((self.retries - 1) * 3) * 1000 + INITIAL_RETRY_SLEEP_BASE_MS,
+ MAX_RETRY_SLEEP_MS,
+ )
+ }
+ }
}
fn maybe_spurious(err: &Error) -> bool {
diff --git a/src/tools/cargo/src/cargo/util/profile.rs b/src/tools/cargo/src/cargo/util/profile.rs
index 79b544d98..29b110492 100644
--- a/src/tools/cargo/src/cargo/util/profile.rs
+++ b/src/tools/cargo/src/cargo/util/profile.rs
@@ -1,4 +1,4 @@
-//! # An internal profiler for Cargo itself
+//! An internal performance profiler for Cargo itself.
//!
//! > **Note**: This might not be the module you are looking for.
//! > For information about how Cargo handles compiler flags with profiles,
diff --git a/src/tools/cargo/src/cargo/util/restricted_names.rs b/src/tools/cargo/src/cargo/util/restricted_names.rs
index 650ae2330..be1811a88 100644
--- a/src/tools/cargo/src/cargo/util/restricted_names.rs
+++ b/src/tools/cargo/src/cargo/util/restricted_names.rs
@@ -83,6 +83,30 @@ pub fn validate_package_name(name: &str, what: &str, help: &str) -> CargoResult<
Ok(())
}
+/// Ensure a package name is [valid][validate_package_name]
+pub fn sanitize_package_name(name: &str, placeholder: char) -> String {
+ let mut slug = String::new();
+ let mut chars = name.chars();
+ if let Some(ch) = chars.next() {
+ if ch.is_digit(10) {
+ slug.push(placeholder);
+ slug.push(ch);
+ } else if unicode_xid::UnicodeXID::is_xid_start(ch) || ch == '_' {
+ slug.push(ch);
+ } else {
+ slug.push(placeholder);
+ }
+ }
+ for ch in chars {
+ if unicode_xid::UnicodeXID::is_xid_continue(ch) || ch == '-' {
+ slug.push(ch);
+ } else {
+ slug.push(placeholder);
+ }
+ }
+ slug
+}
+
/// Check the entire path for names reserved in Windows.
pub fn is_windows_reserved_path(path: &Path) -> bool {
path.iter()
diff --git a/src/tools/cargo/src/cargo/util/toml/embedded.rs b/src/tools/cargo/src/cargo/util/toml/embedded.rs
new file mode 100644
index 000000000..8e41010b4
--- /dev/null
+++ b/src/tools/cargo/src/cargo/util/toml/embedded.rs
@@ -0,0 +1,895 @@
+use anyhow::Context as _;
+
+use crate::util::restricted_names;
+use crate::CargoResult;
+use crate::Config;
+
+const DEFAULT_EDITION: crate::core::features::Edition =
+ crate::core::features::Edition::LATEST_STABLE;
+const DEFAULT_VERSION: &str = "0.0.0";
+const DEFAULT_PUBLISH: bool = false;
+const AUTO_FIELDS: &[&str] = &["autobins", "autoexamples", "autotests", "autobenches"];
+
+pub fn expand_manifest(
+ content: &str,
+ path: &std::path::Path,
+ config: &Config,
+) -> CargoResult<String> {
+ let comment = match extract_comment(content) {
+ Ok(comment) => Some(comment),
+ Err(err) => {
+ log::trace!("failed to extract doc comment: {err}");
+ None
+ }
+ }
+ .unwrap_or_default();
+ let manifest = match extract_manifest(&comment)? {
+ Some(manifest) => Some(manifest),
+ None => {
+ log::trace!("failed to extract manifest");
+ None
+ }
+ }
+ .unwrap_or_default();
+ let manifest = expand_manifest_(&manifest, path, config)
+ .with_context(|| format!("failed to parse manifest at {}", path.display()))?;
+ let manifest = toml::to_string_pretty(&manifest)?;
+ Ok(manifest)
+}
+
+fn expand_manifest_(
+ manifest: &str,
+ path: &std::path::Path,
+ config: &Config,
+) -> CargoResult<toml::Table> {
+ let mut manifest: toml::Table = toml::from_str(&manifest)?;
+
+ for key in ["workspace", "lib", "bin", "example", "test", "bench"] {
+ if manifest.contains_key(key) {
+ anyhow::bail!("`{key}` is not allowed in embedded manifests")
+ }
+ }
+
+ // Prevent looking for a workspace by `read_manifest_from_str`
+ manifest.insert("workspace".to_owned(), toml::Table::new().into());
+
+ let package = manifest
+ .entry("package".to_owned())
+ .or_insert_with(|| toml::Table::new().into())
+ .as_table_mut()
+ .ok_or_else(|| anyhow::format_err!("`package` must be a table"))?;
+ for key in ["workspace", "build", "links"]
+ .iter()
+ .chain(AUTO_FIELDS.iter())
+ {
+ if package.contains_key(*key) {
+ anyhow::bail!("`package.{key}` is not allowed in embedded manifests")
+ }
+ }
+ let file_name = path
+ .file_name()
+ .ok_or_else(|| anyhow::format_err!("no file name"))?
+ .to_string_lossy();
+ let file_stem = path
+ .file_stem()
+ .ok_or_else(|| anyhow::format_err!("no file name"))?
+ .to_string_lossy();
+ let name = sanitize_name(file_stem.as_ref());
+ let bin_name = name.clone();
+ package
+ .entry("name".to_owned())
+ .or_insert(toml::Value::String(name));
+ package
+ .entry("version".to_owned())
+ .or_insert_with(|| toml::Value::String(DEFAULT_VERSION.to_owned()));
+ package.entry("edition".to_owned()).or_insert_with(|| {
+ let _ = config.shell().warn(format_args!(
+ "`package.edition` is unspecifiead, defaulting to `{}`",
+ DEFAULT_EDITION
+ ));
+ toml::Value::String(DEFAULT_EDITION.to_string())
+ });
+ package
+ .entry("build".to_owned())
+ .or_insert_with(|| toml::Value::Boolean(false));
+ package
+ .entry("publish".to_owned())
+ .or_insert_with(|| toml::Value::Boolean(DEFAULT_PUBLISH));
+ for field in AUTO_FIELDS {
+ package
+ .entry(field.to_owned())
+ .or_insert_with(|| toml::Value::Boolean(false));
+ }
+
+ let mut bin = toml::Table::new();
+ bin.insert("name".to_owned(), toml::Value::String(bin_name));
+ bin.insert(
+ "path".to_owned(),
+ toml::Value::String(file_name.into_owned()),
+ );
+ manifest.insert(
+ "bin".to_owned(),
+ toml::Value::Array(vec![toml::Value::Table(bin)]),
+ );
+
+ let release = manifest
+ .entry("profile".to_owned())
+ .or_insert_with(|| toml::Value::Table(Default::default()))
+ .as_table_mut()
+ .ok_or_else(|| anyhow::format_err!("`profile` must be a table"))?
+ .entry("release".to_owned())
+ .or_insert_with(|| toml::Value::Table(Default::default()))
+ .as_table_mut()
+ .ok_or_else(|| anyhow::format_err!("`profile.release` must be a table"))?;
+ release
+ .entry("strip".to_owned())
+ .or_insert_with(|| toml::Value::Boolean(true));
+
+ Ok(manifest)
+}
+
+/// Ensure the package name matches the validation from `ops::cargo_new::check_name`
+fn sanitize_name(name: &str) -> String {
+ let placeholder = if name.contains('_') {
+ '_'
+ } else {
+ // Since embedded manifests only support `[[bin]]`s, prefer arrow-case as that is the
+ // more common convention for CLIs
+ '-'
+ };
+
+ let mut name = restricted_names::sanitize_package_name(name, placeholder);
+
+ loop {
+ if restricted_names::is_keyword(&name) {
+ name.push(placeholder);
+ } else if restricted_names::is_conflicting_artifact_name(&name) {
+ // Being an embedded manifest, we always assume it is a `[[bin]]`
+ name.push(placeholder);
+ } else if name == "test" {
+ name.push(placeholder);
+ } else if restricted_names::is_windows_reserved(&name) {
+ // Go ahead and be consistent across platforms
+ name.push(placeholder);
+ } else {
+ break;
+ }
+ }
+
+ name
+}
+
+/// Locates a "code block manifest" in Rust source.
+fn extract_comment(input: &str) -> CargoResult<String> {
+ let mut doc_fragments = Vec::new();
+ let file = syn::parse_file(input)?;
+ // HACK: `syn` doesn't tell us what kind of comment was used, so infer it from how many
+ // attributes were used
+ let kind = if 1 < file
+ .attrs
+ .iter()
+ .filter(|attr| attr.meta.path().is_ident("doc"))
+ .count()
+ {
+ CommentKind::Line
+ } else {
+ CommentKind::Block
+ };
+ for attr in &file.attrs {
+ if attr.meta.path().is_ident("doc") {
+ doc_fragments.push(DocFragment::new(attr, kind)?);
+ }
+ }
+ if doc_fragments.is_empty() {
+ anyhow::bail!("no doc-comment found");
+ }
+ unindent_doc_fragments(&mut doc_fragments);
+
+ let mut doc_comment = String::new();
+ for frag in &doc_fragments {
+ add_doc_fragment(&mut doc_comment, frag);
+ }
+
+ Ok(doc_comment)
+}
+
+/// A `#[doc]`
+#[derive(Clone, Debug)]
+struct DocFragment {
+ /// The attribute value
+ doc: String,
+ /// Indentation used within `doc
+ indent: usize,
+}
+
+impl DocFragment {
+ fn new(attr: &syn::Attribute, kind: CommentKind) -> CargoResult<Self> {
+ let syn::Meta::NameValue(nv) = &attr.meta else {
+ anyhow::bail!("unsupported attr meta for {:?}", attr.meta.path())
+ };
+ let syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Str(lit), .. }) = &nv.value else {
+ anyhow::bail!("only string literals are supported")
+ };
+ Ok(Self {
+ doc: beautify_doc_string(lit.value(), kind),
+ indent: 0,
+ })
+ }
+}
+
+#[derive(Clone, Copy, PartialEq, Debug)]
+pub enum CommentKind {
+ Line,
+ Block,
+}
+
+/// Makes a doc string more presentable to users.
+/// Used by rustdoc and perhaps other tools, but not by rustc.
+///
+/// See `rustc_ast/util/comments.rs`
+fn beautify_doc_string(data: String, kind: CommentKind) -> String {
+ fn get_vertical_trim(lines: &[&str]) -> Option<(usize, usize)> {
+ let mut i = 0;
+ let mut j = lines.len();
+ // first line of all-stars should be omitted
+ if !lines.is_empty() && lines[0].chars().all(|c| c == '*') {
+ i += 1;
+ }
+
+ // like the first, a last line of all stars should be omitted
+ if j > i && !lines[j - 1].is_empty() && lines[j - 1].chars().all(|c| c == '*') {
+ j -= 1;
+ }
+
+ if i != 0 || j != lines.len() {
+ Some((i, j))
+ } else {
+ None
+ }
+ }
+
+ fn get_horizontal_trim(lines: &[&str], kind: CommentKind) -> Option<String> {
+ let mut i = usize::MAX;
+ let mut first = true;
+
+ // In case we have doc comments like `/**` or `/*!`, we want to remove stars if they are
+ // present. However, we first need to strip the empty lines so they don't get in the middle
+ // when we try to compute the "horizontal trim".
+ let lines = match kind {
+ CommentKind::Block => {
+ // Whatever happens, we skip the first line.
+ let mut i = lines
+ .get(0)
+ .map(|l| {
+ if l.trim_start().starts_with('*') {
+ 0
+ } else {
+ 1
+ }
+ })
+ .unwrap_or(0);
+ let mut j = lines.len();
+
+ while i < j && lines[i].trim().is_empty() {
+ i += 1;
+ }
+ while j > i && lines[j - 1].trim().is_empty() {
+ j -= 1;
+ }
+ &lines[i..j]
+ }
+ CommentKind::Line => lines,
+ };
+
+ for line in lines {
+ for (j, c) in line.chars().enumerate() {
+ if j > i || !"* \t".contains(c) {
+ return None;
+ }
+ if c == '*' {
+ if first {
+ i = j;
+ first = false;
+ } else if i != j {
+ return None;
+ }
+ break;
+ }
+ }
+ if i >= line.len() {
+ return None;
+ }
+ }
+ if lines.is_empty() {
+ None
+ } else {
+ Some(lines[0][..i].into())
+ }
+ }
+
+ let data_s = data.as_str();
+ if data_s.contains('\n') {
+ let mut lines = data_s.lines().collect::<Vec<&str>>();
+ let mut changes = false;
+ let lines = if let Some((i, j)) = get_vertical_trim(&lines) {
+ changes = true;
+ // remove whitespace-only lines from the start/end of lines
+ &mut lines[i..j]
+ } else {
+ &mut lines
+ };
+ if let Some(horizontal) = get_horizontal_trim(lines, kind) {
+ changes = true;
+ // remove a "[ \t]*\*" block from each line, if possible
+ for line in lines.iter_mut() {
+ if let Some(tmp) = line.strip_prefix(&horizontal) {
+ *line = tmp;
+ if kind == CommentKind::Block
+ && (*line == "*" || line.starts_with("* ") || line.starts_with("**"))
+ {
+ *line = &line[1..];
+ }
+ }
+ }
+ }
+ if changes {
+ return lines.join("\n");
+ }
+ }
+ data
+}
+
+/// Removes excess indentation on comments in order for the Markdown
+/// to be parsed correctly. This is necessary because the convention for
+/// writing documentation is to provide a space between the /// or //! marker
+/// and the doc text, but Markdown is whitespace-sensitive. For example,
+/// a block of text with four-space indentation is parsed as a code block,
+/// so if we didn't unindent comments, these list items
+///
+/// /// A list:
+/// ///
+/// /// - Foo
+/// /// - Bar
+///
+/// would be parsed as if they were in a code block, which is likely not what the user intended.
+///
+/// See also `rustc_resolve/rustdoc.rs`
+fn unindent_doc_fragments(docs: &mut [DocFragment]) {
+ // HACK: We can't tell the difference between `#[doc]` and doc-comments, so we can't specialize
+ // the indentation like rustodc does
+ let add = 0;
+
+ // `min_indent` is used to know how much whitespaces from the start of each lines must be
+ // removed. Example:
+ //
+ // ```
+ // /// hello!
+ // #[doc = "another"]
+ // ```
+ //
+ // In here, the `min_indent` is 1 (because non-sugared fragment are always counted with minimum
+ // 1 whitespace), meaning that "hello!" will be considered a codeblock because it starts with 4
+ // (5 - 1) whitespaces.
+ let Some(min_indent) = docs
+ .iter()
+ .map(|fragment| {
+ fragment.doc.as_str().lines().fold(usize::MAX, |min_indent, line| {
+ if line.chars().all(|c| c.is_whitespace()) {
+ min_indent
+ } else {
+ // Compare against either space or tab, ignoring whether they are
+ // mixed or not.
+ let whitespace = line.chars().take_while(|c| *c == ' ' || *c == '\t').count();
+ min_indent.min(whitespace)
+ }
+ })
+ })
+ .min()
+ else {
+ return;
+ };
+
+ for fragment in docs {
+ if fragment.doc.is_empty() {
+ continue;
+ }
+
+ let min_indent = if min_indent > 0 {
+ min_indent - add
+ } else {
+ min_indent
+ };
+
+ fragment.indent = min_indent;
+ }
+}
+
+/// The goal of this function is to apply the `DocFragment` transformation that is required when
+/// transforming into the final Markdown, which is applying the computed indent to each line in
+/// each doc fragment (a `DocFragment` can contain multiple lines in case of `#[doc = ""]`).
+///
+/// Note: remove the trailing newline where appropriate
+///
+/// See also `rustc_resolve/rustdoc.rs`
+fn add_doc_fragment(out: &mut String, frag: &DocFragment) {
+ let s = frag.doc.as_str();
+ let mut iter = s.lines();
+ if s.is_empty() {
+ out.push('\n');
+ return;
+ }
+ while let Some(line) = iter.next() {
+ if line.chars().any(|c| !c.is_whitespace()) {
+ assert!(line.len() >= frag.indent);
+ out.push_str(&line[frag.indent..]);
+ } else {
+ out.push_str(line);
+ }
+ out.push('\n');
+ }
+}
+
+/// Extracts the first `Cargo` fenced code block from a chunk of Markdown.
+fn extract_manifest(comment: &str) -> CargoResult<Option<String>> {
+ use pulldown_cmark::{CodeBlockKind, Event, Options, Parser, Tag};
+
+ // To match librustdoc/html/markdown.rs, opts.
+ let exts = Options::ENABLE_TABLES | Options::ENABLE_FOOTNOTES;
+
+ let md = Parser::new_ext(comment, exts);
+
+ let mut inside = false;
+ let mut output = None;
+
+ for item in md {
+ match item {
+ Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(ref info)))
+ if info.to_lowercase() == "cargo" =>
+ {
+ if output.is_some() {
+ anyhow::bail!("multiple `cargo` manifests present")
+ } else {
+ output = Some(String::new());
+ }
+ inside = true;
+ }
+ Event::Text(ref text) if inside => {
+ let s = output.get_or_insert(String::new());
+ s.push_str(text);
+ }
+ Event::End(Tag::CodeBlock(_)) if inside => {
+ inside = false;
+ }
+ _ => (),
+ }
+ }
+
+ Ok(output)
+}
+
+#[cfg(test)]
+mod test_expand {
+ use super::*;
+
+ macro_rules! si {
+ ($i:expr) => {{
+ expand_manifest(
+ $i,
+ std::path::Path::new("/home/me/test.rs"),
+ &Config::default().unwrap(),
+ )
+ .unwrap_or_else(|err| panic!("{}", err))
+ }};
+ }
+
+ #[test]
+ fn test_default() {
+ snapbox::assert_eq(
+ r#"[[bin]]
+name = "test-"
+path = "test.rs"
+
+[package]
+autobenches = false
+autobins = false
+autoexamples = false
+autotests = false
+build = false
+edition = "2021"
+name = "test-"
+publish = false
+version = "0.0.0"
+
+[profile.release]
+strip = true
+
+[workspace]
+"#,
+ si!(r#"fn main() {}"#),
+ );
+ }
+
+ #[test]
+ fn test_dependencies() {
+ snapbox::assert_eq(
+ r#"[[bin]]
+name = "test-"
+path = "test.rs"
+
+[dependencies]
+time = "0.1.25"
+
+[package]
+autobenches = false
+autobins = false
+autoexamples = false
+autotests = false
+build = false
+edition = "2021"
+name = "test-"
+publish = false
+version = "0.0.0"
+
+[profile.release]
+strip = true
+
+[workspace]
+"#,
+ si!(r#"
+//! ```cargo
+//! [dependencies]
+//! time="0.1.25"
+//! ```
+fn main() {}
+"#),
+ );
+ }
+}
+
+#[cfg(test)]
+mod test_comment {
+ use super::*;
+
+ macro_rules! ec {
+ ($s:expr) => {
+ extract_comment($s).unwrap_or_else(|err| panic!("{}", err))
+ };
+ }
+
+ #[test]
+ fn test_no_comment() {
+ snapbox::assert_eq(
+ "no doc-comment found",
+ extract_comment(
+ r#"
+fn main () {
+}
+"#,
+ )
+ .unwrap_err()
+ .to_string(),
+ );
+ }
+
+ #[test]
+ fn test_no_comment_she_bang() {
+ snapbox::assert_eq(
+ "no doc-comment found",
+ extract_comment(
+ r#"#!/usr/bin/env cargo-eval
+
+fn main () {
+}
+"#,
+ )
+ .unwrap_err()
+ .to_string(),
+ );
+ }
+
+ #[test]
+ fn test_comment() {
+ snapbox::assert_eq(
+ r#"Here is a manifest:
+
+```cargo
+[dependencies]
+time = "*"
+```
+"#,
+ ec!(r#"//! Here is a manifest:
+//!
+//! ```cargo
+//! [dependencies]
+//! time = "*"
+//! ```
+fn main() {}
+"#),
+ );
+ }
+
+ #[test]
+ fn test_comment_shebang() {
+ snapbox::assert_eq(
+ r#"Here is a manifest:
+
+```cargo
+[dependencies]
+time = "*"
+```
+"#,
+ ec!(r#"#!/usr/bin/env cargo-eval
+
+//! Here is a manifest:
+//!
+//! ```cargo
+//! [dependencies]
+//! time = "*"
+//! ```
+fn main() {}
+"#),
+ );
+ }
+
+ #[test]
+ fn test_multiline_comment() {
+ snapbox::assert_eq(
+ r#"Here is a manifest:
+
+```cargo
+[dependencies]
+time = "*"
+```
+"#,
+ ec!(r#"/*!
+Here is a manifest:
+
+```cargo
+[dependencies]
+time = "*"
+```
+*/
+
+fn main() {
+}
+"#),
+ );
+ }
+
+ #[test]
+ fn test_multiline_comment_shebang() {
+ snapbox::assert_eq(
+ r#"Here is a manifest:
+
+```cargo
+[dependencies]
+time = "*"
+```
+"#,
+ ec!(r#"#!/usr/bin/env cargo-eval
+
+/*!
+Here is a manifest:
+
+```cargo
+[dependencies]
+time = "*"
+```
+*/
+
+fn main() {
+}
+"#),
+ );
+ }
+
+ #[test]
+ fn test_multiline_block_comment() {
+ snapbox::assert_eq(
+ r#"Here is a manifest:
+
+```cargo
+[dependencies]
+time = "*"
+```
+"#,
+ ec!(r#"/*!
+ * Here is a manifest:
+ *
+ * ```cargo
+ * [dependencies]
+ * time = "*"
+ * ```
+ */
+fn main() {}
+"#),
+ );
+ }
+
+ #[test]
+ fn test_multiline_block_comment_shebang() {
+ snapbox::assert_eq(
+ r#"Here is a manifest:
+
+```cargo
+[dependencies]
+time = "*"
+```
+"#,
+ ec!(r#"#!/usr/bin/env cargo-eval
+
+/*!
+ * Here is a manifest:
+ *
+ * ```cargo
+ * [dependencies]
+ * time = "*"
+ * ```
+ */
+fn main() {}
+"#),
+ );
+ }
+
+ #[test]
+ fn test_adjacent_comments() {
+ snapbox::assert_eq(
+ r#"Here is a manifest:
+
+```cargo
+[dependencies]
+time = "*"
+```
+"#,
+ ec!(r#"#!/usr/bin/env cargo-eval
+
+// I am a normal comment
+//! Here is a manifest:
+//!
+//! ```cargo
+//! [dependencies]
+//! time = "*"
+//! ```
+
+fn main () {
+}
+"#),
+ );
+ }
+
+ #[test]
+ fn test_doc_attrib() {
+ snapbox::assert_eq(
+ r#"Here is a manifest:
+
+```cargo
+[dependencies]
+time = "*"
+```
+"#,
+ ec!(r###"#!/usr/bin/env cargo-eval
+
+#![doc = r#"Here is a manifest:
+
+```cargo
+[dependencies]
+time = "*"
+```
+"#]
+
+fn main () {
+}
+"###),
+ );
+ }
+}
+
+#[cfg(test)]
+mod test_manifest {
+ use super::*;
+
+ macro_rules! smm {
+ ($c:expr) => {
+ extract_manifest($c)
+ };
+ }
+
+ #[test]
+ fn test_no_code_fence() {
+ assert_eq!(
+ smm!(
+ r#"There is no manifest in this comment.
+"#
+ )
+ .unwrap(),
+ None
+ );
+ }
+
+ #[test]
+ fn test_no_cargo_code_fence() {
+ assert_eq!(
+ smm!(
+ r#"There is no manifest in this comment.
+
+```
+This is not a manifest.
+```
+
+```rust
+println!("Nor is this.");
+```
+
+ Or this.
+"#
+ )
+ .unwrap(),
+ None
+ );
+ }
+
+ #[test]
+ fn test_cargo_code_fence() {
+ assert_eq!(
+ smm!(
+ r#"This is a manifest:
+
+```cargo
+dependencies = { time = "*" }
+```
+"#
+ )
+ .unwrap(),
+ Some(
+ r#"dependencies = { time = "*" }
+"#
+ .into()
+ )
+ );
+ }
+
+ #[test]
+ fn test_mixed_code_fence() {
+ assert_eq!(
+ smm!(
+ r#"This is *not* a manifest:
+
+```
+He's lying, I'm *totally* a manifest!
+```
+
+This *is*:
+
+```cargo
+dependencies = { time = "*" }
+```
+"#
+ )
+ .unwrap(),
+ Some(
+ r#"dependencies = { time = "*" }
+"#
+ .into()
+ )
+ );
+ }
+
+ #[test]
+ fn test_two_cargo_code_fence() {
+ assert!(smm!(
+ r#"This is a manifest:
+
+```cargo
+dependencies = { time = "*" }
+```
+
+So is this, but it doesn't count:
+
+```cargo
+dependencies = { explode = true }
+```
+"#
+ )
+ .is_err());
+ }
+}
diff --git a/src/tools/cargo/src/cargo/util/toml/mod.rs b/src/tools/cargo/src/cargo/util/toml/mod.rs
index 2c213b7f5..2202f6b3b 100644
--- a/src/tools/cargo/src/cargo/util/toml/mod.rs
+++ b/src/tools/cargo/src/cargo/util/toml/mod.rs
@@ -1,4 +1,5 @@
use std::collections::{BTreeMap, BTreeSet, HashMap};
+use std::ffi::OsStr;
use std::fmt::{self, Display, Write};
use std::marker::PhantomData;
use std::path::{Path, PathBuf};
@@ -33,6 +34,7 @@ use crate::util::{
self, config::ConfigRelativePath, validate_package_name, Config, IntoUrl, VersionReqExt,
};
+pub mod embedded;
mod targets;
use self::targets::targets;
@@ -54,13 +56,32 @@ pub fn read_manifest(
path.display(),
source_id
);
- let contents = paths::read(path).map_err(|err| ManifestError::new(err, path.into()))?;
+ let mut contents = paths::read(path).map_err(|err| ManifestError::new(err, path.into()))?;
+ let embedded = is_embedded(path);
+ if embedded {
+ if !config.cli_unstable().script {
+ return Err(ManifestError::new(
+ anyhow::anyhow!("parsing `{}` requires `-Zscript`", path.display()),
+ path.into(),
+ ));
+ }
+ contents = embedded::expand_manifest(&contents, path, config)
+ .map_err(|err| ManifestError::new(err, path.into()))?;
+ }
- read_manifest_from_str(&contents, path, source_id, config)
+ read_manifest_from_str(&contents, path, embedded, source_id, config)
.with_context(|| format!("failed to parse manifest at `{}`", path.display()))
.map_err(|err| ManifestError::new(err, path.into()))
}
+/// See also `bin/cargo/commands/run.rs`s `is_manifest_command`
+pub fn is_embedded(path: &Path) -> bool {
+ let ext = path.extension();
+ ext == Some(OsStr::new("rs")) ||
+ // Provide better errors by not considering directories to be embedded manifests
+ (ext.is_none() && path.is_file())
+}
+
/// Parse an already-loaded `Cargo.toml` as a Cargo manifest.
///
/// This could result in a real or virtual manifest being returned.
@@ -69,9 +90,10 @@ pub fn read_manifest(
/// within the manifest. For virtual manifests, these paths can only
/// come from patched or replaced dependencies. These paths are not
/// canonicalized.
-pub fn read_manifest_from_str(
+fn read_manifest_from_str(
contents: &str,
manifest_file: &Path,
+ embedded: bool,
source_id: SourceId,
config: &Config,
) -> CargoResult<(EitherManifest, Vec<PathBuf>)> {
@@ -127,7 +149,7 @@ pub fn read_manifest_from_str(
}
return if manifest.project.is_some() || manifest.package.is_some() {
let (mut manifest, paths) =
- TomlManifest::to_real_manifest(&manifest, source_id, package_root, config)?;
+ TomlManifest::to_real_manifest(&manifest, embedded, source_id, package_root, config)?;
add_unused(manifest.warnings_mut());
if manifest.targets().iter().all(|t| t.is_custom_build()) {
bail!(
@@ -1573,178 +1595,89 @@ pub struct InheritableFields {
ws_root: PathBuf,
}
-impl InheritableFields {
- pub fn update_deps(&mut self, deps: Option<BTreeMap<String, TomlDependency>>) {
- 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;
- }
-
- pub fn dependencies(&self) -> CargoResult<BTreeMap<String, TomlDependency>> {
- self.dependencies.clone().map_or(
- Err(anyhow!("`workspace.dependencies` was not defined")),
- |d| Ok(d),
- )
- }
-
- pub fn lints(&self) -> CargoResult<TomlLints> {
- self.lints
- .clone()
- .map_or(Err(anyhow!("`workspace.lints` was not defined")), |d| Ok(d))
- }
+/// Defines simple getter methods for inheritable fields.
+macro_rules! inheritable_field_getter {
+ ( $(($key:literal, $field:ident -> $ret:ty),)* ) => (
+ $(
+ #[doc = concat!("Gets the field `workspace.", $key, "`.")]
+ pub fn $field(&self) -> CargoResult<$ret> {
+ let Some(val) = &self.$field else {
+ bail!("`workspace.{}` was not defined", $key);
+ };
+ Ok(val.clone())
+ }
+ )*
+ )
+}
+impl InheritableFields {
+ inheritable_field_getter! {
+ // Please keep this list lexicographically ordered.
+ ("dependencies", dependencies -> BTreeMap<String, TomlDependency>),
+ ("lints", lints -> TomlLints),
+ ("package.authors", authors -> Vec<String>),
+ ("package.badges", badges -> BTreeMap<String, BTreeMap<String, String>>),
+ ("package.categories", categories -> Vec<String>),
+ ("package.description", description -> String),
+ ("package.documentation", documentation -> String),
+ ("package.edition", edition -> String),
+ ("package.exclude", exclude -> Vec<String>),
+ ("package.homepage", homepage -> String),
+ ("package.include", include -> Vec<String>),
+ ("package.keywords", keywords -> Vec<String>),
+ ("package.license", license -> String),
+ ("package.publish", publish -> VecStringOrBool),
+ ("package.repository", repository -> String),
+ ("package.rust-version", rust_version -> String),
+ ("package.version", version -> semver::Version),
+ }
+
+ /// Gets a workspace dependency with the `name`.
pub fn get_dependency(&self, name: &str, package_root: &Path) -> CargoResult<TomlDependency> {
- self.dependencies.clone().map_or(
- Err(anyhow!("`workspace.dependencies` was not defined")),
- |deps| {
- deps.get(name).map_or(
- Err(anyhow!(
- "`dependency.{}` was not found in `workspace.dependencies`",
- name
- )),
- |dep| {
- let mut dep = dep.clone();
- if let TomlDependency::Detailed(detailed) = &mut dep {
- detailed.resolve_path(name, self.ws_root(), package_root)?
- }
- Ok(dep)
- },
- )
- },
- )
- }
-
- pub fn version(&self) -> CargoResult<semver::Version> {
- self.version.clone().map_or(
- Err(anyhow!("`workspace.package.version` was not defined")),
- |d| Ok(d),
- )
- }
-
- pub fn authors(&self) -> CargoResult<Vec<String>> {
- self.authors.clone().map_or(
- Err(anyhow!("`workspace.package.authors` was not defined")),
- |d| Ok(d),
- )
- }
-
- pub fn description(&self) -> CargoResult<String> {
- self.description.clone().map_or(
- Err(anyhow!("`workspace.package.description` was not defined")),
- |d| Ok(d),
- )
- }
-
- pub fn homepage(&self) -> CargoResult<String> {
- self.homepage.clone().map_or(
- Err(anyhow!("`workspace.package.homepage` was not defined")),
- |d| Ok(d),
- )
- }
-
- pub fn documentation(&self) -> CargoResult<String> {
- self.documentation.clone().map_or(
- Err(anyhow!("`workspace.package.documentation` was not defined")),
- |d| Ok(d),
- )
- }
-
- pub fn readme(&self, package_root: &Path) -> CargoResult<StringOrBool> {
- readme_for_package(self.ws_root.as_path(), self.readme.clone()).map_or(
- Err(anyhow!("`workspace.package.readme` was not defined")),
- |readme| {
- let rel_path =
- resolve_relative_path("readme", &self.ws_root, package_root, &readme)?;
- Ok(StringOrBool::String(rel_path))
- },
- )
- }
-
- pub fn keywords(&self) -> CargoResult<Vec<String>> {
- self.keywords.clone().map_or(
- Err(anyhow!("`workspace.package.keywords` was not defined")),
- |d| Ok(d),
- )
- }
-
- pub fn categories(&self) -> CargoResult<Vec<String>> {
- self.categories.clone().map_or(
- Err(anyhow!("`workspace.package.categories` was not defined")),
- |d| Ok(d),
- )
- }
-
- pub fn license(&self) -> CargoResult<String> {
- self.license.clone().map_or(
- Err(anyhow!("`workspace.package.license` was not defined")),
- |d| Ok(d),
- )
+ let Some(deps) = &self.dependencies else {
+ bail!("`workspace.dependencies` was not defined");
+ };
+ let Some(dep) = deps.get(name) else {
+ bail!("`dependency.{name}` was not found in `workspace.dependencies`");
+ };
+ let mut dep = dep.clone();
+ if let TomlDependency::Detailed(detailed) = &mut dep {
+ detailed.resolve_path(name, self.ws_root(), package_root)?;
+ }
+ Ok(dep)
}
+ /// Gets the field `workspace.package.license-file`.
pub fn license_file(&self, package_root: &Path) -> CargoResult<String> {
- self.license_file.clone().map_or(
- Err(anyhow!("`workspace.package.license_file` was not defined")),
- |d| resolve_relative_path("license-file", &self.ws_root, package_root, &d),
- )
- }
-
- pub fn repository(&self) -> CargoResult<String> {
- self.repository.clone().map_or(
- Err(anyhow!("`workspace.package.repository` was not defined")),
- |d| Ok(d),
- )
- }
-
- pub fn publish(&self) -> CargoResult<VecStringOrBool> {
- self.publish.clone().map_or(
- Err(anyhow!("`workspace.package.publish` was not defined")),
- |d| Ok(d),
- )
- }
-
- pub fn edition(&self) -> CargoResult<String> {
- self.edition.clone().map_or(
- Err(anyhow!("`workspace.package.edition` was not defined")),
- |d| Ok(d),
- )
+ let Some(license_file) = &self.license_file else {
+ bail!("`workspace.package.license-file` was not defined");
+ };
+ resolve_relative_path("license-file", &self.ws_root, package_root, license_file)
}
- pub fn rust_version(&self) -> CargoResult<String> {
- self.rust_version.clone().map_or(
- Err(anyhow!("`workspace.package.rust-version` was not defined")),
- |d| Ok(d),
- )
+ /// Gets the field `workspace.package.readme`.
+ pub fn readme(&self, package_root: &Path) -> CargoResult<StringOrBool> {
+ let Some(readme) = readme_for_package(self.ws_root.as_path(), self.readme.as_ref()) else {
+ bail!("`workspace.package.readme` was not defined");
+ };
+ resolve_relative_path("readme", &self.ws_root, package_root, &readme)
+ .map(StringOrBool::String)
}
- pub fn badges(&self) -> CargoResult<BTreeMap<String, BTreeMap<String, String>>> {
- self.badges.clone().map_or(
- Err(anyhow!("`workspace.package.badges` was not defined")),
- |d| Ok(d),
- )
+ pub fn ws_root(&self) -> &PathBuf {
+ &self.ws_root
}
- pub fn exclude(&self) -> CargoResult<Vec<String>> {
- self.exclude.clone().map_or(
- Err(anyhow!("`workspace.package.exclude` was not defined")),
- |d| Ok(d),
- )
+ pub fn update_deps(&mut self, deps: Option<BTreeMap<String, TomlDependency>>) {
+ self.dependencies = deps;
}
- pub fn include(&self) -> CargoResult<Vec<String>> {
- self.include.clone().map_or(
- Err(anyhow!("`workspace.package.include` was not defined")),
- |d| Ok(d),
- )
+ pub fn update_lints(&mut self, lints: Option<TomlLints>) {
+ self.lints = lints;
}
- pub fn ws_root(&self) -> &PathBuf {
- &self.ws_root
+ pub fn update_ws_path(&mut self, ws_root: PathBuf) {
+ self.ws_root = ws_root;
}
}
@@ -1975,6 +1908,7 @@ impl TomlManifest {
pub fn to_real_manifest(
me: &Rc<TomlManifest>,
+ embedded: bool,
source_id: SourceId,
package_root: &Path,
config: &Config,
@@ -2412,7 +2346,6 @@ impl TomlManifest {
let empty_features = BTreeMap::new();
let summary = Summary::new(
- config,
pkgid,
deps,
me.features.as_ref().unwrap_or(&empty_features),
@@ -2442,7 +2375,8 @@ impl TomlManifest {
.readme
.clone()
.map(|mw| mw.resolve("readme", || inherit()?.readme(package_root)))
- .transpose()?,
+ .transpose()?
+ .as_ref(),
),
authors: package
.authors
@@ -2643,6 +2577,7 @@ impl TomlManifest {
package.metabuild.clone().map(|sov| sov.0),
resolve_behavior,
rustflags,
+ embedded,
);
if package.license_file.is_some() && package.license.is_some() {
manifest.warnings_mut().add_warning(
@@ -3039,7 +2974,7 @@ fn inheritable_from_path(
}
/// Returns the name of the README file for a [`TomlPackage`].
-pub fn readme_for_package(package_root: &Path, readme: Option<StringOrBool>) -> Option<String> {
+pub fn readme_for_package(package_root: &Path, readme: Option<&StringOrBool>) -> Option<String> {
match &readme {
None => default_readme_from_package_root(package_root),
Some(value) => match value {
diff --git a/src/tools/cargo/src/cargo/util/toml_mut/manifest.rs b/src/tools/cargo/src/cargo/util/toml_mut/manifest.rs
index f3fc150e1..5529b8029 100644
--- a/src/tools/cargo/src/cargo/util/toml_mut/manifest.rs
+++ b/src/tools/cargo/src/cargo/util/toml_mut/manifest.rs
@@ -496,6 +496,11 @@ fn fix_feature_activations(
for idx in remove_list.iter().rev() {
feature_values.remove(*idx);
}
+ if !remove_list.is_empty() {
+ // HACK: Instead of cleaning up the users formatting from having removed a feature, we just
+ // re-format the whole feature list
+ feature_values.fmt();
+ }
if status == DependencyStatus::Required {
for value in feature_values.iter_mut() {
@@ -511,13 +516,13 @@ fn fix_feature_activations(
} = parsed_value
{
if dep_name == dep_key && weak {
- *value = format!("{dep_name}/{dep_feature}").into();
+ let mut new_value = toml_edit::Value::from(format!("{dep_name}/{dep_feature}"));
+ *new_value.decor_mut() = value.decor().clone();
+ *value = new_value;
}
}
}
}
-
- feature_values.fmt();
}
pub fn str_or_1_len_table(item: &toml_edit::Item) -> bool {
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 63f07ca55..c9dae918c 100644
--- a/src/tools/cargo/src/doc/contrib/src/process/index.md
+++ b/src/tools/cargo/src/doc/contrib/src/process/index.md
@@ -90,7 +90,7 @@ implemented.
The Cargo project uses several bots:
* [GitHub Actions] are used to automatically run all tests for each PR.
-* [triagebot] automatically assigns reviewers for PRs, see [Assignment] for
+* [triagebot] automatically assigns reviewers for PRs, see [PR Assignment] for
how to configure.
* [bors] is used to merge PRs. See [The merging process].
* [triagebot] is used for assigning issues to non-members, see [Issue
@@ -100,20 +100,20 @@ The Cargo project uses several bots:
[bors]: https://buildbot2.rust-lang.org/homu/
[The merging process]: working-on-cargo.md#the-merging-process
[GitHub Actions]: https://github.com/features/actions
-[triagebot]: https://github.com/rust-lang/triagebot/wiki
+[triagebot]: https://forge.rust-lang.org/triagebot/index.html
[rfcbot]: https://github.com/rust-lang/rfcbot-rs
-[Assignment]: https://github.com/rust-lang/triagebot/wiki/Assignment
+[PR Assignment]: https://forge.rust-lang.org/triagebot/pr-assignment.html
## Issue assignment
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
+by entering the text `@rustbot claim` in a comment. See the [Issue Assignment] docs
on how this works.
-[Assignment]: https://github.com/rust-lang/triagebot/wiki/Assignment
+[Issue Assignment]: https://forge.rust-lang.org/triagebot/issue-assignment.html
[team]: https://www.rust-lang.org/governance/teams/dev-tools#cargo
[Zulip]: https://rust-lang.zulipchat.com/#narrow/stream/246057-t-cargo
[issue-feature-request]: https://github.com/rust-lang/cargo/labels/C-feature-request
diff --git a/src/tools/cargo/src/doc/contrib/src/process/working-on-cargo.md b/src/tools/cargo/src/doc/contrib/src/process/working-on-cargo.md
index e90bb8588..1567197c4 100644
--- a/src/tools/cargo/src/doc/contrib/src/process/working-on-cargo.md
+++ b/src/tools/cargo/src/doc/contrib/src/process/working-on-cargo.md
@@ -135,7 +135,7 @@ More information about these commands can be found at the [shortcuts documentati
[`S-waiting-on-review`]: https://github.com/rust-lang/cargo/labels/S-waiting-on-review
[`S-waiting-on-author`]: https://github.com/rust-lang/cargo/labels/S-waiting-on-author
[`@rustbot`]: https://github.com/rustbot
-[shortcuts documentation]: https://github.com/rust-lang/triagebot/wiki/Shortcuts
+[shortcuts documentation]: https://forge.rust-lang.org/triagebot/shortcuts.html
## The merging process
diff --git a/src/tools/cargo/src/doc/man/cargo-install.md b/src/tools/cargo/src/doc/man/cargo-install.md
index 385ed27c2..e6786318f 100644
--- a/src/tools/cargo/src/doc/man/cargo-install.md
+++ b/src/tools/cargo/src/doc/man/cargo-install.md
@@ -18,7 +18,7 @@ cargo-install --- Build and install a Rust binary
This command manages Cargo's local set of installed binary crates. Only
packages which have executable `[[bin]]` or `[[example]]` targets can be
installed, and all executables are installed into the installation root's
-`bin` folder.
+`bin` folder. By default only binaries, not examples, are installed.
{{> description-install-root }}
@@ -141,7 +141,7 @@ Install only the specified binary.
{{/option}}
{{#option "`--bins`" }}
-Install all binaries.
+Install all binaries. This is the default behavior.
{{/option}}
{{#option "`--example` _name_..." }}
diff --git a/src/tools/cargo/src/doc/man/cargo-test.md b/src/tools/cargo/src/doc/man/cargo-test.md
index 49792d6be..75bf72b30 100644
--- a/src/tools/cargo/src/doc/man/cargo-test.md
+++ b/src/tools/cargo/src/doc/man/cargo-test.md
@@ -59,12 +59,19 @@ on writing doc tests.
### Working directory of tests
-The working directory of every test is set to the root directory of the package
-the test belongs to.
-Setting the working directory of tests to the package's root directory makes it
+The working directory when running each unit and integration test is set to the
+root directory of the package the test belongs to.
+Setting the working directory of tests to the package's root directory makes it
possible for tests to reliably access the package's files using relative paths,
regardless from where `cargo test` was executed from.
+For documentation tests, the working directory when invoking `rustdoc` is set to
+the workspace root directory, and is also the directory `rustdoc` uses as the
+compilation directory of each documentation test.
+The working directory when running each documentation test is set to the root
+directory of the package the test belongs to, and is controlled via `rustdoc`'s
+`--test-run-directory` option.
+
## OPTIONS
### Test Options
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 9108d6165..9610b72f0 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
@@ -410,6 +410,7 @@ OPTIONS
<https://doc.rust-lang.org/cargo/reference/config.html>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number
of parallel jobs to the number of logical CPUs plus provided value.
+ If a string default is provided, it sets the value back to defaults.
Should not be 0.
--keep-going
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-build.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-build.txt
index ff8bdb5ba..e396410d3 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-build.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-build.txt
@@ -341,6 +341,7 @@ OPTIONS
<https://doc.rust-lang.org/cargo/reference/config.html>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number
of parallel jobs to the number of logical CPUs plus provided value.
+ If a string default is provided, it sets the value back to defaults.
Should not be 0.
--keep-going
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-check.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-check.txt
index bf8cb48f3..9814f445d 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-check.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-check.txt
@@ -326,6 +326,7 @@ OPTIONS
<https://doc.rust-lang.org/cargo/reference/config.html>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number
of parallel jobs to the number of logical CPUs plus provided value.
+ If a string default is provided, it sets the value back to defaults.
Should not be 0.
--keep-going
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-doc.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-doc.txt
index 825032826..09f9b68c9 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-doc.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-doc.txt
@@ -297,6 +297,7 @@ OPTIONS
<https://doc.rust-lang.org/cargo/reference/config.html>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number
of parallel jobs to the number of logical CPUs plus provided value.
+ If a string default is provided, it sets the value back to defaults.
Should not be 0.
--keep-going
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-fix.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-fix.txt
index 87d72ad38..b83c360eb 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-fix.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-fix.txt
@@ -399,6 +399,7 @@ OPTIONS
<https://doc.rust-lang.org/cargo/reference/config.html>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number
of parallel jobs to the number of logical CPUs plus provided value.
+ If a string default is provided, it sets the value back to defaults.
Should not be 0.
--keep-going
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 7aefd3492..a5b696111 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
@@ -13,7 +13,8 @@ DESCRIPTION
This command manages Cargo’s local set of installed binary crates.
Only packages which have executable [[bin]] or [[example]] targets can
be installed, and all executables are installed into the installation
- root’s bin folder.
+ root’s bin folder. By default only binaries, not examples, are
+ installed.
The installation root is determined, in order of precedence:
@@ -137,7 +138,7 @@ OPTIONS
Install only the specified binary.
--bins
- Install all binaries.
+ Install all binaries. This is the default behavior.
--example name…
Install only the specified example.
@@ -273,6 +274,7 @@ OPTIONS
<https://doc.rust-lang.org/cargo/reference/config.html>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number
of parallel jobs to the number of logical CPUs plus provided value.
+ If a string default is provided, it sets the value back to defaults.
Should not be 0.
--keep-going
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-package.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-package.txt
index 960e0248e..1201f3d07 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-package.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-package.txt
@@ -191,6 +191,7 @@ OPTIONS
<https://doc.rust-lang.org/cargo/reference/config.html>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number
of parallel jobs to the number of logical CPUs plus provided value.
+ If a string default is provided, it sets the value back to defaults.
Should not be 0.
--keep-going
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-publish.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-publish.txt
index d35172ad7..e8850e3d4 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-publish.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-publish.txt
@@ -157,6 +157,7 @@ OPTIONS
<https://doc.rust-lang.org/cargo/reference/config.html>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number
of parallel jobs to the number of logical CPUs plus provided value.
+ If a string default is provided, it sets the value back to defaults.
Should not be 0.
--keep-going
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-run.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-run.txt
index f6782be11..5fcfe66b4 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-run.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-run.txt
@@ -245,6 +245,7 @@ OPTIONS
<https://doc.rust-lang.org/cargo/reference/config.html>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number
of parallel jobs to the number of logical CPUs plus provided value.
+ If a string default is provided, it sets the value back to defaults.
Should not be 0.
--keep-going
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-rustc.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-rustc.txt
index cc4241f93..7a70c5363 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-rustc.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-rustc.txt
@@ -343,6 +343,7 @@ OPTIONS
<https://doc.rust-lang.org/cargo/reference/config.html>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number
of parallel jobs to the number of logical CPUs plus provided value.
+ If a string default is provided, it sets the value back to defaults.
Should not be 0.
--keep-going
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-rustdoc.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-rustdoc.txt
index 6a32a6b6e..4db66b3a8 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-rustdoc.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-rustdoc.txt
@@ -313,6 +313,7 @@ OPTIONS
<https://doc.rust-lang.org/cargo/reference/config.html>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number
of parallel jobs to the number of logical CPUs plus provided value.
+ If a string default is provided, it sets the value back to defaults.
Should not be 0.
--keep-going
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 9e26f8aae..7955b0e3d 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
@@ -53,11 +53,18 @@ DESCRIPTION
information on writing doc tests.
Working directory of tests
- The working directory of every test is set to the root directory of the
- package the test belongs to. Setting the working directory of tests to
- the package’s root directory makes it possible for tests to reliably
- access the package’s files using relative paths, regardless from where
- cargo test was executed from.
+ The working directory when running each unit and integration test is set
+ to the root directory of the package the test belongs to. Setting the
+ working directory of tests to the package’s root directory makes it
+ possible for tests to reliably access the package’s files using
+ relative paths, regardless from where cargo test was executed from.
+
+ For documentation tests, the working directory when invoking rustdoc is
+ set to the workspace root directory, and is also the directory rustdoc
+ uses as the compilation directory of each documentation test. The
+ working directory when running each documentation test is set to the
+ root directory of the package the test belongs to, and is controlled via
+ rustdoc’s --test-run-directory option.
OPTIONS
Test Options
@@ -432,6 +439,7 @@ OPTIONS
<https://doc.rust-lang.org/cargo/reference/config.html>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number
of parallel jobs to the number of logical CPUs plus provided value.
+ If a string default is provided, it sets the value back to defaults.
Should not be 0.
--keep-going
diff --git a/src/tools/cargo/src/doc/man/includes/options-jobs.md b/src/tools/cargo/src/doc/man/includes/options-jobs.md
index 274263866..0030e18d8 100644
--- a/src/tools/cargo/src/doc/man/includes/options-jobs.md
+++ b/src/tools/cargo/src/doc/man/includes/options-jobs.md
@@ -2,6 +2,7 @@
Number of parallel jobs to run. May also be specified with the
`build.jobs` [config value](../reference/config.html). Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string `default` is provided, it sets the value back to defaults.
Should not be 0.
{{/option}}
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 df0101be5..70ae187a7 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-bench.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-bench.md
@@ -476,7 +476,8 @@ Rust test harness runs benchmarks serially in a single thread.
<dd class="option-desc">Number of parallel jobs to run. May also be specified with the
<code>build.jobs</code> <a href="../reference/config.html">config value</a>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string <code>default</code> is provided, it sets the value back to defaults.
Should not be 0.</dd>
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-build.md b/src/tools/cargo/src/doc/src/commands/cargo-build.md
index 6e3cf157a..525ab14e5 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-build.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-build.md
@@ -402,7 +402,8 @@ requires the <code>-Z unstable-options</code> flag to enable (see
<dd class="option-desc">Number of parallel jobs to run. May also be specified with the
<code>build.jobs</code> <a href="../reference/config.html">config value</a>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string <code>default</code> is provided, it sets the value back to defaults.
Should not be 0.</dd>
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-check.md b/src/tools/cargo/src/doc/src/commands/cargo-check.md
index 2070293ac..4dbc97ad8 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-check.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-check.md
@@ -383,7 +383,8 @@ requires the <code>-Z unstable-options</code> flag to enable (see
<dd class="option-desc">Number of parallel jobs to run. May also be specified with the
<code>build.jobs</code> <a href="../reference/config.html">config value</a>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string <code>default</code> is provided, it sets the value back to defaults.
Should not be 0.</dd>
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-doc.md b/src/tools/cargo/src/doc/src/commands/cargo-doc.md
index e0e5c8ed2..d68bb84e7 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-doc.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-doc.md
@@ -357,7 +357,8 @@ requires the <code>-Z unstable-options</code> flag to enable (see
<dd class="option-desc">Number of parallel jobs to run. May also be specified with the
<code>build.jobs</code> <a href="../reference/config.html">config value</a>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string <code>default</code> is provided, it sets the value back to defaults.
Should not be 0.</dd>
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-fix.md b/src/tools/cargo/src/doc/src/commands/cargo-fix.md
index 1b9ec6a85..2bf83fc2e 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-fix.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-fix.md
@@ -463,7 +463,8 @@ requires the <code>-Z unstable-options</code> flag to enable (see
<dd class="option-desc">Number of parallel jobs to run. May also be specified with the
<code>build.jobs</code> <a href="../reference/config.html">config value</a>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string <code>default</code> is provided, it sets the value back to defaults.
Should not be 0.</dd>
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 5d413010c..af8efcae8 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-install.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-install.md
@@ -18,7 +18,7 @@ cargo-install --- Build and install a Rust binary
This command manages Cargo's local set of installed binary crates. Only
packages which have executable `[[bin]]` or `[[example]]` targets can be
installed, and all executables are installed into the installation root's
-`bin` folder.
+`bin` folder. By default only binaries, not examples, are installed.
The installation root is determined, in order of precedence:
@@ -150,7 +150,7 @@ same time.</dd>
<dt class="option-term" id="option-cargo-install---bins"><a class="option-anchor" href="#option-cargo-install---bins"></a><code>--bins</code></dt>
-<dd class="option-desc">Install all binaries.</dd>
+<dd class="option-desc">Install all binaries. This is the default behavior.</dd>
<dt class="option-term" id="option-cargo-install---example"><a class="option-anchor" href="#option-cargo-install---example"></a><code>--example</code> <em>name</em>…</dt>
@@ -312,7 +312,8 @@ offline.</p>
<dd class="option-desc">Number of parallel jobs to run. May also be specified with the
<code>build.jobs</code> <a href="../reference/config.html">config value</a>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string <code>default</code> is provided, it sets the value back to defaults.
Should not be 0.</dd>
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-package.md b/src/tools/cargo/src/doc/src/commands/cargo-package.md
index 776b150cf..f9c7c552d 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-package.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-package.md
@@ -227,7 +227,8 @@ offline.</p>
<dd class="option-desc">Number of parallel jobs to run. May also be specified with the
<code>build.jobs</code> <a href="../reference/config.html">config value</a>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string <code>default</code> is provided, it sets the value back to defaults.
Should not be 0.</dd>
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-publish.md b/src/tools/cargo/src/doc/src/commands/cargo-publish.md
index 1f4fbebb8..fe37d9f97 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-publish.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-publish.md
@@ -193,7 +193,8 @@ offline.</p>
<dd class="option-desc">Number of parallel jobs to run. May also be specified with the
<code>build.jobs</code> <a href="../reference/config.html">config value</a>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string <code>default</code> is provided, it sets the value back to defaults.
Should not be 0.</dd>
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-run.md b/src/tools/cargo/src/doc/src/commands/cargo-run.md
index f6f5ec2a3..bd3e4724a 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-run.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-run.md
@@ -299,7 +299,8 @@ requires the <code>-Z unstable-options</code> flag to enable (see
<dd class="option-desc">Number of parallel jobs to run. May also be specified with the
<code>build.jobs</code> <a href="../reference/config.html">config value</a>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string <code>default</code> is provided, it sets the value back to defaults.
Should not be 0.</dd>
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-rustc.md b/src/tools/cargo/src/doc/src/commands/cargo-rustc.md
index 946298af9..2147d617c 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-rustc.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-rustc.md
@@ -396,7 +396,8 @@ requires the <code>-Z unstable-options</code> flag to enable (see
<dd class="option-desc">Number of parallel jobs to run. May also be specified with the
<code>build.jobs</code> <a href="../reference/config.html">config value</a>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string <code>default</code> is provided, it sets the value back to defaults.
Should not be 0.</dd>
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-rustdoc.md b/src/tools/cargo/src/doc/src/commands/cargo-rustdoc.md
index 8467da2a3..22c1c8322 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-rustdoc.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-rustdoc.md
@@ -376,7 +376,8 @@ requires the <code>-Z unstable-options</code> flag to enable (see
<dd class="option-desc">Number of parallel jobs to run. May also be specified with the
<code>build.jobs</code> <a href="../reference/config.html">config value</a>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string <code>default</code> is provided, it sets the value back to defaults.
Should not be 0.</dd>
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 24fcc70ff..e38e9929e 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-test.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-test.md
@@ -59,12 +59,19 @@ on writing doc tests.
### Working directory of tests
-The working directory of every test is set to the root directory of the package
-the test belongs to.
-Setting the working directory of tests to the package's root directory makes it
+The working directory when running each unit and integration test is set to the
+root directory of the package the test belongs to.
+Setting the working directory of tests to the package's root directory makes it
possible for tests to reliably access the package's files using relative paths,
regardless from where `cargo test` was executed from.
+For documentation tests, the working directory when invoking `rustdoc` is set to
+the workspace root directory, and is also the directory `rustdoc` uses as the
+compilation directory of each documentation test.
+The working directory when running each documentation test is set to the root
+directory of the package the test belongs to, and is controlled via `rustdoc`'s
+`--test-run-directory` option.
+
## OPTIONS
### Test Options
@@ -503,7 +510,8 @@ includes an option to control the number of threads used:
<dd class="option-desc">Number of parallel jobs to run. May also be specified with the
<code>build.jobs</code> <a href="../reference/config.html">config value</a>. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string <code>default</code> is provided, it sets the value back to defaults.
Should not be 0.</dd>
diff --git a/src/tools/cargo/src/doc/src/faq.md b/src/tools/cargo/src/doc/src/faq.md
index abe90c000..e4a753413 100644
--- a/src/tools/cargo/src/doc/src/faq.md
+++ b/src/tools/cargo/src/doc/src/faq.md
@@ -259,3 +259,49 @@ Some issues we've seen historically which can cause crates to get rebuilt are:
If after trying to debug your issue, however, you're still running into problems
then feel free to [open an
issue](https://github.com/rust-lang/cargo/issues/new)!
+
+### What does "version conflict" mean and how to resolve it?
+
+> failed to select a version for `x` which could resolve this conflict
+
+Have you seen the error message above?
+
+This is one of the most annoying error message for Cargo users. There are several
+situations may lead us to a version conflict. Below we'll walk through possible
+causes and provide diagnostic techniques to help you out there:
+
+- The project and its dependencies use [links] to repeatedly link the local
+ library. Cargo forbids linking two packages with the same native library, so
+ even with multiple layers of dependencies it is not allowed. In this case, the
+ error message will prompt: `Only one package in the dependency graph may specify
+ the same links value`, you may need to manually check and delete duplicate link
+ values. The community also have [conventions in place] to alleviate this.
+
+- When depending on different crates in the project, if these crates use the same
+ dependent library, but the version used is restricted, making it impossible to
+ determine the correct version, it will also cause conflicts. The error message
+ will prompt: `all possible versions conflict with previously selected packages`.
+ You may need to modify the version requirements to make them consistent.
+
+- If there are multiple versions of dependencies in the project, when using
+ [`direct-minimal-versions`], the minimum version requirements cannot be met,
+ which will cause conflicts. You may need to modify version requirements of your
+ direct dependencies to meet the minimum SemVer version accordingly.
+
+- If the dependent crate does not have the features you choose, it will also
+ cause conflicts. At this time, you need to check the dependent version and its
+ features.
+
+- Conflicts may occur when merging branches or PRs, if there are non-trivial
+ conflicts, you can reset all "yours" changes, fix all other conflicts in the
+ branch, and then run some cargo command (like `cargo tree` or `cargo check`),
+ which should re-update the lockfile with your own local changes. If you previously
+ ran some `cargo update` commands in your branch, you can re-run them that this
+ time. The community has been looking to resolve merge conflicts with `Cargo.lock`
+ and `Cargo.toml` using a [custom merge tool].
+
+
+[links]: https://doc.rust-lang.org/cargo/reference/resolver.html#links
+[conventions in place]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#-sys-packages
+[`direct-minimal-versions`]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#direct-minimal-versions
+[custom merge tool]: https://github.com/rust-lang/cargo/issues/1818
diff --git a/src/tools/cargo/src/doc/src/reference/config.md b/src/tools/cargo/src/doc/src/reference/config.md
index c57a45f67..30053bb18 100644
--- a/src/tools/cargo/src/doc/src/reference/config.md
+++ b/src/tools/cargo/src/doc/src/reference/config.md
@@ -370,13 +370,14 @@ recursive_example = "rr --example recursions"
The `[build]` table controls build-time operations and compiler settings.
##### `build.jobs`
-* Type: integer
+* Type: integer or string
* Default: number of logical CPUs
* Environment: `CARGO_BUILD_JOBS`
Sets the maximum number of compiler processes to run in parallel. If negative,
it sets the maximum number of compiler processes to the number of logical CPUs
-plus provided value. Should not be 0.
+plus provided value. Should not be 0. If a string `default` is provided, it sets
+the value back to defaults.
Can be overridden with the `--jobs` CLI option.
diff --git a/src/tools/cargo/src/doc/src/reference/environment-variables.md b/src/tools/cargo/src/doc/src/reference/environment-variables.md
index 95c4c87fb..353742877 100644
--- a/src/tools/cargo/src/doc/src/reference/environment-variables.md
+++ b/src/tools/cargo/src/doc/src/reference/environment-variables.md
@@ -274,6 +274,7 @@ on the platform:
* Windows: `PATH`
* macOS: `DYLD_FALLBACK_LIBRARY_PATH`
* Unix: `LD_LIBRARY_PATH`
+* AIX: `LIBPATH`
The value is extended from the existing value when Cargo starts. macOS has
special consideration where if `DYLD_FALLBACK_LIBRARY_PATH` is not already
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 9e5be3e5b..3eed6ef39 100644
--- a/src/tools/cargo/src/doc/src/reference/registry-index.md
+++ b/src/tools/cargo/src/doc/src/reference/registry-index.md
@@ -80,6 +80,8 @@ harder to support older versions of Cargo that lack `{prefix}`/`{lowerprefix}`.
For example, nginx rewrite rules can easily construct `{prefix}` but can't
perform case-conversion to construct `{lowerprefix}`.
+### Name restrictions
+
Registries should consider enforcing limitations on package names added to
their index. Cargo itself allows names with any [alphanumeric], `-`, or `_`
characters. [crates.io] imposes its own limitations, including the following:
@@ -98,6 +100,14 @@ attacks](https://en.wikipedia.org/wiki/IDN_homograph_attack) and other
concerns in [UTR36](https://www.unicode.org/reports/tr36/) and
[UTS39](https://www.unicode.org/reports/tr39/).
+### Version uniqueness
+
+Indexes *must* ensure that each version only appears once for each package.
+This includes ignoring SemVer build metadata.
+For example, the index must *not* contain two entries with a version `1.0.7` and `1.0.7+extra`.
+
+### JSON schema
+
Each line in a package file contains a JSON object that describes a published
version of the package. The following is a pretty-printed example with comments
explaining the format of the entry.
diff --git a/src/tools/cargo/src/doc/src/reference/resolver.md b/src/tools/cargo/src/doc/src/reference/resolver.md
index af02d6cf2..151648f43 100644
--- a/src/tools/cargo/src/doc/src/reference/resolver.md
+++ b/src/tools/cargo/src/doc/src/reference/resolver.md
@@ -50,7 +50,7 @@ Tilde | `~1.2` | <code>>=1.2.0,&nbsp;<1.3.0</code> | Minimum version, with restr
Wildcard | `1.*` | <code>>=1.0.0,&nbsp;<2.0.0</code> | Any version in the `*` position.
Equals | `=1.2.3` | <code>=1.2.3</code> | Exactly the specified version only.
Comparison | `>1.1` | <code>>=1.2.0</code> | Naive numeric comparison of specified digits.
-Compound | <code>>=1.2,&nbsp;<1.5</code> | <code>>1.2.0,&nbsp;<1.5.0</code> | Multiple requirements that must be simultaneously satisfied.
+Compound | <code>>=1.2,&nbsp;<1.5</code> | <code>>=1.2.0,&nbsp;<1.5.0</code> | Multiple requirements that must be simultaneously satisfied.
When multiple packages specify a dependency for a common package, the resolver
attempts to ensure that they use the same version of that common package, as
diff --git a/src/tools/cargo/src/doc/src/reference/specifying-dependencies.md b/src/tools/cargo/src/doc/src/reference/specifying-dependencies.md
index 8d9eac308..8941e67ad 100644
--- a/src/tools/cargo/src/doc/src/reference/specifying-dependencies.md
+++ b/src/tools/cargo/src/doc/src/reference/specifying-dependencies.md
@@ -107,6 +107,43 @@ Here are some examples of comparison requirements:
As shown in the examples above, multiple version requirements can be
separated with a comma, e.g., `>= 1.2, < 1.5`.
+> **Recommendation:** When in doubt, use the default version requirement operator.
+>
+> In rare circumstances, a package with a "public dependency"
+> (re-exports the dependency or interoperates with it in its public API)
+> that is compatible with multiple semver-incompatible versions
+> (e.g. only uses a simple type that hasn't changed between releases, like an `Id`)
+> may support users choosing which version of the "public dependency" to use.
+> In this case, a version requirement like `">=0.4, <2"` may be of interest.
+> *However* users of the package will likely run into errors and need to to
+> manually select a version of the "public dependency" via `cargo update` if
+> they also depend on it as Cargo might pick different versions of the "public
+> dependency" when [resolving dependency versions](resolver.md) (see
+> [#10599]).
+>
+> Avoid constraining the upper bound of a version to be anything less than the
+> next semver incompatible version
+> (e.g. avoid `">=2.0, <2.4"`) as other packages in the dependency tree may
+> require a newer version, leading to an unresolvable error (see #6584).
+> Consider whether controlling the version in your [`Cargo.lock`] would be more
+> appropriate.
+>
+> In some instances this won't matter or the benefits might outweigh the cost, including:
+> - When no one else depends on your package e.g. it only has a `[[bin]]`
+> - When depending on a pre-release package and wishing to avoid breaking
+> changes then a fully specified `"=1.2.3-alpha.3"` might be warranted (see
+> [#2222])
+> - When a library re-exports a proc-macro but the proc-macro generates code that
+> calls into the re-exporting library then a fully specified `=1.2.3` might be
+> warranted to ensure the proc-macro isn't newer than the re-exporting library
+> and generating code that uses parts of the API that don't exist within the
+> current version
+
+[`Cargo.lock`]: ../guide/cargo-toml-vs-cargo-lock.md
+[#2222]: https://github.com/rust-lang/cargo/issues/2222
+[#6584]: https://github.com/rust-lang/cargo/issues/6584
+[#10599]: https://github.com/rust-lang/cargo/issues/10599
+
### Specifying dependencies from other registries
To specify a dependency from a registry other than [crates.io], first the
@@ -140,7 +177,8 @@ Cargo will fetch the `git` repository at this location then look for a
of a workspace and setting `git` to the repository containing the workspace).
Since we haven’t specified any other information, Cargo assumes that
-we intend to use the latest commit on the main branch to build our package.
+we intend to use the latest commit on the default branch branch
+to build our package, which may not necessarily be the main branch.
You can combine the `git` key with the `rev`, `tag`, or `branch` keys to
specify something else. Here's an example of specifying that you want to use
the latest commit on a branch named `next`:
diff --git a/src/tools/cargo/src/doc/src/reference/unstable.md b/src/tools/cargo/src/doc/src/reference/unstable.md
index 7484db9b5..b59319196 100644
--- a/src/tools/cargo/src/doc/src/reference/unstable.md
+++ b/src/tools/cargo/src/doc/src/reference/unstable.md
@@ -52,10 +52,12 @@ how the feature works:
```
Each new feature described below should explain how to use it.
+For the latest nightly, see the [nightly version] of this page.
[config file]: config.md
[nightly channel]: ../../book/appendix-07-nightly-rust.html
[stabilized]: https://doc.crates.io/contrib/process/unstable.html#stabilization
+[nightly version]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#script
### List of unstable features
@@ -85,7 +87,6 @@ Each new feature described below should explain how to use it.
* [host-config](#host-config) --- Allows setting `[target]`-like configuration settings for host build targets.
* [target-applies-to-host](#target-applies-to-host) --- Alters whether certain flags will be passed to host build targets.
* rustdoc
- * [`doctest-in-workspace`](#doctest-in-workspace) --- Fixes workspace-relative paths when running doctests.
* [rustdoc-map](#rustdoc-map) --- Provides mappings for documentation to link to external sites like [docs.rs](https://docs.rs/).
* [scrape-examples](#scrape-examples) --- Shows examples within documentation.
* `Cargo.toml` extensions
@@ -107,6 +108,7 @@ Each new feature described below should explain how to use it.
* [registry-auth](#registry-auth) --- Adds support for authenticated registries, and generate registry authentication tokens using asymmetric cryptography.
* Other
* [gitoxide](#gitoxide) --- Use `gitoxide` instead of `git2` for a set of operations.
+ * [script](#script) --- Enable support for single-file `.rs` packages.
### allow-features
@@ -450,27 +452,30 @@ cargo check --keep-going -Z unstable-options
### config-include
* Tracking Issue: [#7723](https://github.com/rust-lang/cargo/issues/7723)
+This feature requires the `-Zconfig-include` command-line option.
+
The `include` key in a config file can be used to load another config file. It
-takes a string for a path to another file relative to the config file, or a
-list of strings. It requires the `-Zconfig-include` command-line option.
+takes a string for a path to another file relative to the config file, or an
+array of config file paths. Only path ending with `.toml` is accepted.
```toml
-# .cargo/config
-include = '../../some-common-config.toml'
-```
-
-The config values are first loaded from the include path, and then the config
-file's own values are merged on top of it.
+# a path ending with `.toml`
+include = "path/to/mordor.toml"
-This can be paired with [config-cli](#config-cli) to specify a file to load
-from the command-line. Pass a path to a config file as the argument to
-`--config`:
-
-```console
-cargo +nightly -Zunstable-options -Zconfig-include --config somefile.toml build
+# or an array of paths
+include = ["frodo.toml", "samwise.toml"]
```
-CLI paths are relative to the current working directory.
+Unlike other config values, the merge behavior of the `include` key is
+different. When a config file contains an `include` key:
+
+1. The config values are first loaded from the `include` path.
+ * If the value of the `include` key is an array of paths, the config values
+ are loaded and merged from left to right for each path.
+ * Recurse this step if the config values from the `include` path also
+ contain an `include` key.
+2. Then, the config file's own values are merged on top of the config
+ from the `include` path.
### target-applies-to-host
* Original Pull Request: [#9322](https://github.com/rust-lang/cargo/pull/9322)
@@ -1185,24 +1190,6 @@ cargo +nightly -Zunstable-options config get build.rustflags
If no config value is included, it will display all config values. See the
`--help` output for more options available.
-### `doctest-in-workspace`
-
-* Tracking Issue: [#9427](https://github.com/rust-lang/cargo/issues/9427)
-
-The `-Z doctest-in-workspace` flag changes the behavior of the current working
-directory used when running doctests. Historically, Cargo has run `rustdoc
---test` relative to the root of the package, with paths relative from that
-root. However, this is inconsistent with how `rustc` and `rustdoc` are
-normally run in a workspace, where they are run relative to the workspace
-root. This inconsistency causes problems in various ways, such as when passing
-RUSTDOCFLAGS with relative paths, or dealing with diagnostic output.
-
-The `-Z doctest-in-workspace` flag causes cargo to switch to running `rustdoc`
-from the root of the workspace. It also passes the `--test-run-directory` to
-`rustdoc` so that when *running* the tests, they are run from the root of the
-package. This preserves backwards compatibility and is consistent with how
-normal unittests are run.
-
### rustc `--print`
* Tracking Issue: [#9357](https://github.com/rust-lang/cargo/issues/9357)
@@ -1392,6 +1379,113 @@ Valid operations are the following:
* 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.
+### script
+
+* Tracking Issue: [#12207](https://github.com/rust-lang/cargo/issues/12207)
+
+Cargo can directly run `.rs` files as:
+```console
+$ cargo +nightly -Zscript file.rs
+```
+where `file.rs` can be as simple as:
+```rust
+fn main() {}
+```
+
+A user may optionally specify a manifest in a `cargo` code fence in a module-level comment, like:
+```rust
+#!/usr/bin/env -S cargo +nightly -Zscript
+
+//! ```cargo
+//! [dependencies]
+//! clap = { version = "4.2", features = ["derive"] }
+//! ```
+
+use clap::Parser;
+
+#[derive(Parser, Debug)]
+#[clap(version)]
+struct Args {
+ #[clap(short, long, help = "Path to config")]
+ config: Option<std::path::PathBuf>,
+}
+
+fn main() {
+ let args = Args::parse();
+ println!("{:?}", args);
+}
+```
+
+#### Single-file packages
+
+In addition to today's multi-file packages (`Cargo.toml` file with other `.rs`
+files), we are adding the concept of single-file packages which may contain an
+embedded manifest. There is no required distinguishment for a single-file
+`.rs` package from any other `.rs` file.
+
+Single-file packages may be selected via `--manifest-path`, like
+`cargo test --manifest-path foo.rs`. Unlike `Cargo.toml`, these files cannot be auto-discovered.
+
+A single-file package may contain an embedded manifest. An embedded manifest
+is stored using `TOML` in a markdown code-fence with `cargo` at the start of the
+infostring inside a target-level doc-comment. It is an error to have multiple
+`cargo` code fences in the target-level doc-comment. We can relax this later,
+either merging the code fences or ignoring later code fences.
+
+Supported forms of embedded manifest are:
+``````rust
+//! ```cargo
+//! ```
+``````
+``````rust
+/*!
+ * ```cargo
+ * ```
+ */
+``````
+
+Inferred / defaulted manifest fields:
+- `package.name = <slugified file stem>`
+- `package.version = "0.0.0"` to [call attention to this crate being used in unexpected places](https://matklad.github.io/2021/08/22/large-rust-workspaces.html#Smaller-Tips)
+- `package.publish = false` to avoid accidental publishes, particularly if we
+ later add support for including them in a workspace.
+- `package.edition = <current>` to avoid always having to add an embedded
+ manifest at the cost of potentially breaking scripts on rust upgrades
+ - Warn when `edition` is unspecified to raise awareness of this
+
+Disallowed manifest fields:
+- `[workspace]`, `[lib]`, `[[bin]]`, `[[example]]`, `[[test]]`, `[[bench]]`
+- `package.workspace`, `package.build`, `package.links`, `package.autobins`, `package.autoexamples`, `package.autotests`, `package.autobenches`
+
+The default `CARGO_TARGET_DIR` for single-file packages is at `$CARGO_HOME/target/<hash>`:
+- Avoid conflicts from multiple single-file packages being in the same directory
+- Avoid problems with the single-file package's parent directory being read-only
+- Avoid cluttering the user's directory
+
+The lockfile for single-file packages will be placed in `CARGO_TARGET_DIR`. In
+the future, when workspaces are supported, that will allow a user to have a
+persistent lockfile.
+
+#### Manifest-commands
+
+You may pass a manifest directly to the `cargo` command, without a subcommand,
+like `foo/Cargo.toml` or a single-file package like `foo.rs`. This is mostly
+intended for being put in `#!` lines.
+
+The precedence for how to interpret `cargo <subcommand>` is
+1. Built-in xor single-file packages
+2. Aliases
+3. External subcommands
+
+A parameter is identified as a manifest-command if it has one of:
+- Path separators
+- A `.rs` extension
+- The file name is `Cargo.toml`
+
+Differences between `cargo run --manifest-path <path>` and `cargo <path>`
+- `cargo <path>` runs with the config for `<path>` and not the current dir, more like `cargo install --path <path>`
+- `cargo <path>` is at a verbosity level below the normal default. Pass `-v` to get normal output.
+
### `[lints]`
* Tracking Issue: [#12115](https://github.com/rust-lang/cargo/issues/12115)
@@ -1693,3 +1787,11 @@ See [Registry Protocols](registries.md#registry-protocols) for more information.
The [`cargo logout`] command has been stabilized in the 1.70 release.
[target triple]: ../appendix/glossary.md#target '"target" (glossary)'
+
+
+### `doctest-in-workspace`
+
+The `-Z doctest-in-workspace` option for `cargo test` has been stabilized and
+enabled by default in the 1.72 release. See the
+[`cargo test` documentation](../commands/cargo-test.md#working-directory-of-tests)
+for more information about the working directory for compiling and running tests.
diff --git a/src/tools/cargo/src/etc/man/cargo-bench.1 b/src/tools/cargo/src/etc/man/cargo-bench.1
index 44ff593fd..993dd3415 100644
--- a/src/tools/cargo/src/etc/man/cargo-bench.1
+++ b/src/tools/cargo/src/etc/man/cargo-bench.1
@@ -497,7 +497,8 @@ Rust test harness runs benchmarks serially in a single thread.
Number of parallel jobs to run. May also be specified with the
\fBbuild.jobs\fR \fIconfig value\fR <https://doc.rust\-lang.org/cargo/reference/config.html>\&. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string \fBdefault\fR is provided, it sets the value back to defaults.
Should not be 0.
.RE
.sp
diff --git a/src/tools/cargo/src/etc/man/cargo-build.1 b/src/tools/cargo/src/etc/man/cargo-build.1
index 80ae4ac90..4ee6a0d76 100644
--- a/src/tools/cargo/src/etc/man/cargo-build.1
+++ b/src/tools/cargo/src/etc/man/cargo-build.1
@@ -412,7 +412,8 @@ Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details.
Number of parallel jobs to run. May also be specified with the
\fBbuild.jobs\fR \fIconfig value\fR <https://doc.rust\-lang.org/cargo/reference/config.html>\&. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string \fBdefault\fR is provided, it sets the value back to defaults.
Should not be 0.
.RE
.sp
diff --git a/src/tools/cargo/src/etc/man/cargo-check.1 b/src/tools/cargo/src/etc/man/cargo-check.1
index cf7a66d89..1aada2a21 100644
--- a/src/tools/cargo/src/etc/man/cargo-check.1
+++ b/src/tools/cargo/src/etc/man/cargo-check.1
@@ -393,7 +393,8 @@ Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details.
Number of parallel jobs to run. May also be specified with the
\fBbuild.jobs\fR \fIconfig value\fR <https://doc.rust\-lang.org/cargo/reference/config.html>\&. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string \fBdefault\fR is provided, it sets the value back to defaults.
Should not be 0.
.RE
.sp
diff --git a/src/tools/cargo/src/etc/man/cargo-doc.1 b/src/tools/cargo/src/etc/man/cargo-doc.1
index 63ce2a050..24621e9f6 100644
--- a/src/tools/cargo/src/etc/man/cargo-doc.1
+++ b/src/tools/cargo/src/etc/man/cargo-doc.1
@@ -360,7 +360,8 @@ Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details.
Number of parallel jobs to run. May also be specified with the
\fBbuild.jobs\fR \fIconfig value\fR <https://doc.rust\-lang.org/cargo/reference/config.html>\&. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string \fBdefault\fR is provided, it sets the value back to defaults.
Should not be 0.
.RE
.sp
diff --git a/src/tools/cargo/src/etc/man/cargo-fix.1 b/src/tools/cargo/src/etc/man/cargo-fix.1
index 51b1e3fd6..7f2a34cda 100644
--- a/src/tools/cargo/src/etc/man/cargo-fix.1
+++ b/src/tools/cargo/src/etc/man/cargo-fix.1
@@ -488,7 +488,8 @@ Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details.
Number of parallel jobs to run. May also be specified with the
\fBbuild.jobs\fR \fIconfig value\fR <https://doc.rust\-lang.org/cargo/reference/config.html>\&. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string \fBdefault\fR is provided, it sets the value back to defaults.
Should not be 0.
.RE
.sp
diff --git a/src/tools/cargo/src/etc/man/cargo-install.1 b/src/tools/cargo/src/etc/man/cargo-install.1
index a9eb6266b..917c0d0e1 100644
--- a/src/tools/cargo/src/etc/man/cargo-install.1
+++ b/src/tools/cargo/src/etc/man/cargo-install.1
@@ -17,7 +17,7 @@ cargo\-install \[em] Build and install a Rust binary
This command manages Cargo\[cq]s local set of installed binary crates. Only
packages which have executable \fB[[bin]]\fR or \fB[[example]]\fR targets can be
installed, and all executables are installed into the installation root\[cq]s
-\fBbin\fR folder.
+\fBbin\fR folder. By default only binaries, not examples, are installed.
.sp
The installation root is determined, in order of precedence:
.sp
@@ -177,7 +177,7 @@ Install only the specified binary.
.sp
\fB\-\-bins\fR
.RS 4
-Install all binaries.
+Install all binaries. This is the default behavior.
.RE
.sp
\fB\-\-example\fR \fIname\fR\[u2026]
@@ -338,7 +338,8 @@ May also be specified with the \fBnet.offline\fR \fIconfig value\fR <https://doc
Number of parallel jobs to run. May also be specified with the
\fBbuild.jobs\fR \fIconfig value\fR <https://doc.rust\-lang.org/cargo/reference/config.html>\&. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string \fBdefault\fR is provided, it sets the value back to defaults.
Should not be 0.
.RE
.sp
diff --git a/src/tools/cargo/src/etc/man/cargo-package.1 b/src/tools/cargo/src/etc/man/cargo-package.1
index 9f4847d7d..8a7b1c191 100644
--- a/src/tools/cargo/src/etc/man/cargo-package.1
+++ b/src/tools/cargo/src/etc/man/cargo-package.1
@@ -234,7 +234,8 @@ May also be specified with the \fBnet.offline\fR \fIconfig value\fR <https://doc
Number of parallel jobs to run. May also be specified with the
\fBbuild.jobs\fR \fIconfig value\fR <https://doc.rust\-lang.org/cargo/reference/config.html>\&. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string \fBdefault\fR is provided, it sets the value back to defaults.
Should not be 0.
.RE
.sp
diff --git a/src/tools/cargo/src/etc/man/cargo-publish.1 b/src/tools/cargo/src/etc/man/cargo-publish.1
index a54a7bcda..d18f9e690 100644
--- a/src/tools/cargo/src/etc/man/cargo-publish.1
+++ b/src/tools/cargo/src/etc/man/cargo-publish.1
@@ -184,7 +184,8 @@ May also be specified with the \fBnet.offline\fR \fIconfig value\fR <https://doc
Number of parallel jobs to run. May also be specified with the
\fBbuild.jobs\fR \fIconfig value\fR <https://doc.rust\-lang.org/cargo/reference/config.html>\&. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string \fBdefault\fR is provided, it sets the value back to defaults.
Should not be 0.
.RE
.sp
diff --git a/src/tools/cargo/src/etc/man/cargo-run.1 b/src/tools/cargo/src/etc/man/cargo-run.1
index 7a85298cc..1c182ad1a 100644
--- a/src/tools/cargo/src/etc/man/cargo-run.1
+++ b/src/tools/cargo/src/etc/man/cargo-run.1
@@ -297,7 +297,8 @@ Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details.
Number of parallel jobs to run. May also be specified with the
\fBbuild.jobs\fR \fIconfig value\fR <https://doc.rust\-lang.org/cargo/reference/config.html>\&. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string \fBdefault\fR is provided, it sets the value back to defaults.
Should not be 0.
.RE
.sp
diff --git a/src/tools/cargo/src/etc/man/cargo-rustc.1 b/src/tools/cargo/src/etc/man/cargo-rustc.1
index 6e901d9ec..50df99656 100644
--- a/src/tools/cargo/src/etc/man/cargo-rustc.1
+++ b/src/tools/cargo/src/etc/man/cargo-rustc.1
@@ -411,7 +411,8 @@ Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details.
Number of parallel jobs to run. May also be specified with the
\fBbuild.jobs\fR \fIconfig value\fR <https://doc.rust\-lang.org/cargo/reference/config.html>\&. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string \fBdefault\fR is provided, it sets the value back to defaults.
Should not be 0.
.RE
.sp
diff --git a/src/tools/cargo/src/etc/man/cargo-rustdoc.1 b/src/tools/cargo/src/etc/man/cargo-rustdoc.1
index 0c9a0e74a..1792c6e2f 100644
--- a/src/tools/cargo/src/etc/man/cargo-rustdoc.1
+++ b/src/tools/cargo/src/etc/man/cargo-rustdoc.1
@@ -379,7 +379,8 @@ Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details.
Number of parallel jobs to run. May also be specified with the
\fBbuild.jobs\fR \fIconfig value\fR <https://doc.rust\-lang.org/cargo/reference/config.html>\&. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string \fBdefault\fR is provided, it sets the value back to defaults.
Should not be 0.
.RE
.sp
diff --git a/src/tools/cargo/src/etc/man/cargo-test.1 b/src/tools/cargo/src/etc/man/cargo-test.1
index 1ee2f7672..802169815 100644
--- a/src/tools/cargo/src/etc/man/cargo-test.1
+++ b/src/tools/cargo/src/etc/man/cargo-test.1
@@ -54,11 +54,18 @@ and may change in the future; beware of depending on it.
See the \fIrustdoc book\fR <https://doc.rust\-lang.org/rustdoc/> for more information
on writing doc tests.
.SS "Working directory of tests"
-The working directory of every test is set to the root directory of the package
-the test belongs to.
-Setting the working directory of tests to the package\[cq]s root directory makes it
+The working directory when running each unit and integration test is set to the
+root directory of the package the test belongs to.
+Setting the working directory of tests to the package\[cq]s root directory makes it
possible for tests to reliably access the package\[cq]s files using relative paths,
regardless from where \fBcargo test\fR was executed from.
+.sp
+For documentation tests, the working directory when invoking \fBrustdoc\fR is set to
+the workspace root directory, and is also the directory \fBrustdoc\fR uses as the
+compilation directory of each documentation test.
+The working directory when running each documentation test is set to the root
+directory of the package the test belongs to, and is controlled via \fBrustdoc\fR\[cq]s
+\fB\-\-test\-run\-directory\fR option.
.SH "OPTIONS"
.SS "Test Options"
.sp
@@ -523,7 +530,8 @@ cargo test \-j 2 \-\- \-\-test\-threads=2
Number of parallel jobs to run. May also be specified with the
\fBbuild.jobs\fR \fIconfig value\fR <https://doc.rust\-lang.org/cargo/reference/config.html>\&. Defaults to
the number of logical CPUs. If negative, it sets the maximum number of
-parallel jobs to the number of logical CPUs plus provided value.
+parallel jobs to the number of logical CPUs plus provided value. If
+a string \fBdefault\fR is provided, it sets the value back to defaults.
Should not be 0.
.RE
.sp
diff --git a/src/tools/cargo/tests/internal.rs b/src/tools/cargo/tests/internal.rs
deleted file mode 100644
index c42cfa8f0..000000000
--- a/src/tools/cargo/tests/internal.rs
+++ /dev/null
@@ -1,107 +0,0 @@
-//! Tests for internal code checks.
-
-#![allow(clippy::all)]
-
-use std::fs;
-
-#[test]
-fn check_forbidden_code() {
- // Do not use certain macros, functions, etc.
- if !cargo_util::is_ci() {
- // Only check these on CI, otherwise it could be annoying.
- use std::io::Write;
- writeln!(
- std::io::stderr(),
- "\nSkipping check_forbidden_code test, set CI=1 to enable"
- )
- .unwrap();
- return;
- }
- let root_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src");
- for entry in walkdir::WalkDir::new(&root_path)
- .into_iter()
- .filter_entry(|e| e.path() != root_path.join("doc"))
- .filter_map(|e| e.ok())
- {
- let path = entry.path();
- if !entry
- .file_name()
- .to_str()
- .map(|s| s.ends_with(".rs"))
- .unwrap_or(false)
- {
- continue;
- }
- eprintln!("checking {}", path.display());
- let c = fs::read_to_string(path).unwrap();
- for (line_index, line) in c.lines().enumerate() {
- if line.trim().starts_with("//") {
- continue;
- }
- if line_has_print(line) {
- if entry.file_name().to_str().unwrap() == "cargo_new.rs" && line.contains("Hello") {
- // An exception.
- continue;
- }
- panic!(
- "found print macro in {}:{}\n\n{}\n\n\
- print! macros should not be used in Cargo because they can panic.\n\
- Use one of the drop_print macros instead.\n\
- ",
- path.display(),
- line_index,
- line
- );
- }
- if line_has_macro(line, "dbg") {
- panic!(
- "found dbg! macro in {}:{}\n\n{}\n\n\
- dbg! should not be used outside of debugging.",
- path.display(),
- line_index,
- line
- );
- }
- }
- }
-}
-
-fn line_has_print(line: &str) -> bool {
- line_has_macro(line, "print")
- || line_has_macro(line, "eprint")
- || line_has_macro(line, "println")
- || line_has_macro(line, "eprintln")
-}
-
-#[test]
-fn line_has_print_works() {
- assert!(line_has_print("print!"));
- assert!(line_has_print("println!"));
- assert!(line_has_print("eprint!"));
- assert!(line_has_print("eprintln!"));
- assert!(line_has_print("(print!(\"hi!\"))"));
- assert!(!line_has_print("print"));
- assert!(!line_has_print("i like to print things"));
- assert!(!line_has_print("drop_print!"));
- assert!(!line_has_print("drop_println!"));
- assert!(!line_has_print("drop_eprint!"));
- assert!(!line_has_print("drop_eprintln!"));
-}
-
-fn line_has_macro(line: &str, mac: &str) -> bool {
- for (i, _) in line.match_indices(mac) {
- if line.get(i + mac.len()..i + mac.len() + 1) != Some("!") {
- continue;
- }
- if i == 0 {
- return true;
- }
- // Check for identifier boundary start.
- let prev1 = line.get(i - 1..i).unwrap().chars().next().unwrap();
- if prev1.is_alphanumeric() || prev1 == '_' {
- continue;
- }
- return true;
- }
- false
-}
diff --git a/src/tools/cargo/tests/testsuite/bench.rs b/src/tools/cargo/tests/testsuite/bench.rs
index 60ad2b60d..581acbe15 100644
--- a/src/tools/cargo/tests/testsuite/bench.rs
+++ b/src/tools/cargo/tests/testsuite/bench.rs
@@ -313,9 +313,8 @@ fn cargo_bench_failing_test() {
[FINISHED] bench [optimized] target(s) in [..]
[RUNNING] [..] (target/release/deps/foo-[..][EXE])",
)
- .with_stdout_contains(
- "[..]thread '[..]' panicked at 'assertion failed: `(left == right)`[..]",
- )
+ .with_stdout_contains("[..]thread '[..]' panicked at[..]")
+ .with_stdout_contains("[..]assertion failed[..]")
.with_stdout_contains("[..]left: `\"hello\"`[..]")
.with_stdout_contains("[..]right: `\"nope\"`[..]")
.with_stdout_contains("[..]src/main.rs:15[..]")
diff --git a/src/tools/cargo/tests/testsuite/build.rs b/src/tools/cargo/tests/testsuite/build.rs
index 7b555a71b..8cb064a6f 100644
--- a/src/tools/cargo/tests/testsuite/build.rs
+++ b/src/tools/cargo/tests/testsuite/build.rs
@@ -1334,13 +1334,13 @@ fn cargo_default_env_metadata_env_var() {
[COMPILING] bar v0.0.1 ([CWD]/bar)
[RUNNING] `rustc --crate-name bar bar/src/lib.rs [..]--crate-type dylib \
--emit=[..]link \
- -C prefer-dynamic[..]-C debuginfo=2 \
+ -C prefer-dynamic[..]-C debuginfo=2 [..]\
-C metadata=[..] \
--out-dir [..] \
-L dependency=[CWD]/target/debug/deps`
[COMPILING] foo v0.0.1 ([CWD])
[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib \
- --emit=[..]link[..]-C debuginfo=2 \
+ --emit=[..]link[..]-C debuginfo=2 [..]\
-C metadata=[..] \
-C extra-filename=[..] \
--out-dir [..] \
@@ -1362,13 +1362,13 @@ fn cargo_default_env_metadata_env_var() {
[COMPILING] bar v0.0.1 ([CWD]/bar)
[RUNNING] `rustc --crate-name bar bar/src/lib.rs [..]--crate-type dylib \
--emit=[..]link \
- -C prefer-dynamic[..]-C debuginfo=2 \
+ -C prefer-dynamic[..]-C debuginfo=2 [..]\
-C metadata=[..] \
--out-dir [..] \
-L dependency=[CWD]/target/debug/deps`
[COMPILING] foo v0.0.1 ([CWD])
[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib \
- --emit=[..]link[..]-C debuginfo=2 \
+ --emit=[..]link[..]-C debuginfo=2 [..]\
-C metadata=[..] \
-C extra-filename=[..] \
--out-dir [..] \
@@ -2053,7 +2053,7 @@ fn verbose_build() {
"\
[COMPILING] foo v0.0.1 ([CWD])
[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib \
- --emit=[..]link[..]-C debuginfo=2 \
+ --emit=[..]link[..]-C debuginfo=2 [..]\
-C metadata=[..] \
--out-dir [..] \
-L dependency=[CWD]/target/debug/deps`
@@ -4074,7 +4074,7 @@ fn message_format_json_forward_stderr() {
},
"profile":{
"debug_assertions":false,
- "debuginfo":null,
+ "debuginfo":0,
"opt_level":"3",
"overflow_checks": false,
"test":false
@@ -5432,7 +5432,7 @@ fn targets_selected_all() {
// Unit tests.
.with_stderr_contains(
"[RUNNING] `rustc --crate-name foo src/main.rs [..]--emit=[..]link[..]\
- -C debuginfo=2 --test [..]",
+ -C debuginfo=2 [..]--test [..]",
)
.run();
}
@@ -5449,7 +5449,7 @@ fn all_targets_no_lib() {
// Unit tests.
.with_stderr_contains(
"[RUNNING] `rustc --crate-name foo src/main.rs [..]--emit=[..]link[..]\
- -C debuginfo=2 --test [..]",
+ -C debuginfo=2 [..]--test [..]",
)
.run();
}
@@ -5566,6 +5566,8 @@ fn good_jobs() {
p.cargo("build --jobs 1").run();
p.cargo("build --jobs -1").run();
+
+ p.cargo("build --jobs default").run();
}
#[cargo_test]
@@ -5599,8 +5601,8 @@ fn invalid_jobs() {
.run();
p.cargo("build --jobs over9000")
- .with_status(1)
- .with_stderr("error: Invalid value: could not parse `over9000` as a number")
+ .with_status(101)
+ .with_stderr("error: could not parse `over9000`. Number of parallel jobs should be `default` or a number.")
.run();
}
@@ -5920,7 +5922,7 @@ fn build_lib_only() {
"\
[COMPILING] foo v0.0.1 ([CWD])
[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib \
- --emit=[..]link[..]-C debuginfo=2 \
+ --emit=[..]link[..]-C debuginfo=2 [..]\
-C metadata=[..] \
--out-dir [..] \
-L dependency=[CWD]/target/debug/deps`
diff --git a/src/tools/cargo/tests/testsuite/build_script.rs b/src/tools/cargo/tests/testsuite/build_script.rs
index 80a24960e..4840356c6 100644
--- a/src/tools/cargo/tests/testsuite/build_script.rs
+++ b/src/tools/cargo/tests/testsuite/build_script.rs
@@ -1755,7 +1755,7 @@ fn build_cmd_with_a_build_cmd() {
--extern a=[..]liba[..].rlib`
[RUNNING] `[..]/foo-[..]/build-script-build`
[RUNNING] `rustc --crate-name foo [..]lib.rs [..]--crate-type lib \
- --emit=[..]link[..]-C debuginfo=2 \
+ --emit=[..]link[..]-C debuginfo=2 [..]\
-C metadata=[..] \
--out-dir [..] \
-L [..]target/debug/deps`
@@ -1926,7 +1926,6 @@ fn output_separate_lines_new() {
.run();
}
-#[cfg(not(windows))] // FIXME(#867)
#[cargo_test]
fn code_generation() {
let p = project()
@@ -1976,7 +1975,7 @@ fn code_generation() {
"\
[COMPILING] foo v0.5.0 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
-[RUNNING] `target/debug/foo`",
+[RUNNING] `target/debug/foo[EXE]`",
)
.with_stdout("Hello, World!")
.run();
@@ -5108,7 +5107,7 @@ fn duplicate_script_with_extra_env() {
p.cargo("test --workspace -Z doctest-xcompile --doc --target")
.arg(&target)
.masquerade_as_nightly_cargo(&["doctest-xcompile"])
- .with_stdout_contains("test src/lib.rs - (line 2) ... ok")
+ .with_stdout_contains("test foo/src/lib.rs - (line 2) ... ok")
.run();
}
}
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/add_basic/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/add_basic/mod.rs
index 33889dffa..67cd948ae 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/add_basic/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/add_basic/mod.rs
@@ -2,12 +2,23 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/add_multiple/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/add_multiple/mod.rs
index a9cc20575..ce5e9b71d 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/add_multiple/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/add_multiple/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-package1", "my-package2"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/add_normalized_name_external/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/add_normalized_name_external/mod.rs
index 63605d8dc..ced39b99c 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/add_normalized_name_external/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/add_normalized_name_external/mod.rs
@@ -2,12 +2,28 @@ 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::init();
+ cargo_test_support::registry::Package::new("linked-hash-map", "0.5.4")
+ .feature("clippy", &[])
+ .feature("heapsize", &[])
+ .feature("heapsize_impl", &[])
+ .feature("nightly", &[])
+ .feature("serde", &[])
+ .feature("serde_impl", &[])
+ .feature("serde_test", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("inflector", "0.11.4")
+ .feature("default", &["heavyweight", "lazy_static", "regex"])
+ .feature("heavyweight", &[])
+ .feature("lazy_static", &[])
+ .feature("regex", &[])
+ .feature("unstable", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/invalid_git_external/in b/src/tools/cargo/tests/testsuite/cargo_add/add_toolchain/in
index 6c6a27fcf..6c6a27fcf 120000
--- a/src/tools/cargo/tests/testsuite/cargo_add/invalid_git_external/in
+++ b/src/tools/cargo/tests/testsuite/cargo_add/add_toolchain/in
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/invalid_git_external/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/add_toolchain/mod.rs
index 705182f20..905b8c8a2 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/invalid_git_external/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/add_toolchain/mod.rs
@@ -2,25 +2,20 @@ 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;
- let git_url = url::Url::from_directory_path(cwd.join("does-not-exist"))
- .unwrap()
- .to_string();
snapbox::cmd::Command::cargo_ui()
.arg("add")
- .args(["fake-git", "--git", &git_url])
+ .arg_line("+nightly")
.current_dir(cwd)
.assert()
- .code(101)
+ .failure()
.stdout_matches_path(curr_dir!().join("stdout.log"))
.stderr_matches_path(curr_dir!().join("stderr.log"));
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/invalid_git_external/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/add_toolchain/out/Cargo.toml
index 3ecdb6681..3ecdb6681 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/invalid_git_external/out/Cargo.toml
+++ b/src/tools/cargo/tests/testsuite/cargo_add/add_toolchain/out/Cargo.toml
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/add_toolchain/stderr.log b/src/tools/cargo/tests/testsuite/cargo_add/add_toolchain/stderr.log
new file mode 100644
index 000000000..0593685ad
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_add/add_toolchain/stderr.log
@@ -0,0 +1,2 @@
+error: invalid character `+` in dependency name: `+nightly`
+ Use `cargo +nightly add` if you meant to use the `nightly` toolchain.
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/invalid_git_external/stdout.log b/src/tools/cargo/tests/testsuite/cargo_add/add_toolchain/stdout.log
index e69de29bb..e69de29bb 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/invalid_git_external/stdout.log
+++ b/src/tools/cargo/tests/testsuite/cargo_add/add_toolchain/stdout.log
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/build/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/build/mod.rs
index 130ecfbb0..001dd3a8f 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/build/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/build/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-build-package1", "my-build-package2"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/build_prefer_existing_version/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/build_prefer_existing_version/mod.rs
index b0bb2e03b..285ec658a 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/build_prefer_existing_version/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/build_prefer_existing_version/mod.rs
@@ -2,11 +2,23 @@ use cargo_test_support::compare::assert_ui;
use cargo_test_support::prelude::*;
use cargo_test_support::Project;
-use crate::cargo_add::init_alt_registry;
-
#[cargo_test]
fn case() {
- init_alt_registry();
+ cargo_test_support::registry::alt_init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("cargo-list-test-fixture-dependency", ver)
+ .alternative(true)
+ .publish();
+ }
+
let project =
Project::from_template("tests/testsuite/cargo_add/build_prefer_existing_version/in");
let project_root = project.root();
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/change_rename_target/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/change_rename_target/mod.rs
index 94309b3ab..d1540c8ad 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/change_rename_target/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/change_rename_target/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-package1", "my-package2"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/cyclic_features/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/cyclic_features/mod.rs
index 5dffac323..8b4c6123a 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/cyclic_features/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/cyclic_features/mod.rs
@@ -2,12 +2,17 @@ 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::init();
+ cargo_test_support::registry::Package::new("test_cyclic_features", "0.1.1")
+ .feature("default", &["feature-one", "feature-two"])
+ .feature("feature-one", &["feature-two"])
+ .feature("feature-two", &["feature-one"])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/default_features/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/default_features/mod.rs
index 88bdd8065..9d313b9d9 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/default_features/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/default_features/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-package1", "my-package2"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/deprecated_default_features/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/deprecated_default_features/mod.rs
index 10d4e4e98..c4fdd4f3e 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/deprecated_default_features/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/deprecated_default_features/mod.rs
@@ -2,12 +2,23 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/deprecated_section/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/deprecated_section/mod.rs
index 10d4e4e98..c4fdd4f3e 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/deprecated_section/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/deprecated_section/mod.rs
@@ -2,12 +2,23 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/detect_workspace_inherit/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/detect_workspace_inherit/mod.rs
index 065fb4f93..2b9550ce0 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/detect_workspace_inherit/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/detect_workspace_inherit/mod.rs
@@ -2,12 +2,12 @@ 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::init();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/detect_workspace_inherit_features/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/detect_workspace_inherit_features/mod.rs
index 11ab2b1bf..8067166dc 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/detect_workspace_inherit_features/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/detect_workspace_inherit_features/mod.rs
@@ -2,12 +2,12 @@ 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::init();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/detect_workspace_inherit_optional/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/detect_workspace_inherit_optional/mod.rs
index 7557b520d..423f1a26d 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/detect_workspace_inherit_optional/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/detect_workspace_inherit_optional/mod.rs
@@ -2,12 +2,12 @@ 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::init();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/dev/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/dev/mod.rs
index 112e92285..c838f1eac 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/dev/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/dev/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-dev-package1", "my-dev-package2"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/dev_build_conflict/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/dev_build_conflict/mod.rs
index 3f57c6b76..70432b529 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/dev_build_conflict/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/dev_build_conflict/mod.rs
@@ -2,12 +2,23 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/dev_prefer_existing_version/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/dev_prefer_existing_version/mod.rs
index 1785ac820..2d3698c14 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/dev_prefer_existing_version/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/dev_prefer_existing_version/mod.rs
@@ -2,12 +2,25 @@ use cargo_test_support::compare::assert_ui;
use cargo_test_support::prelude::*;
use cargo_test_support::Project;
-use crate::cargo_add::init_alt_registry;
use cargo_test_support::curr_dir;
#[cargo_test]
fn case() {
- init_alt_registry();
+ cargo_test_support::registry::alt_init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("cargo-list-test-fixture-dependency", ver)
+ .alternative(true)
+ .publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/dry_run/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/dry_run/mod.rs
index 209d20873..438ec7b73 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/dry_run/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/dry_run/mod.rs
@@ -2,12 +2,23 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
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
index f6c507188..d612a07f7 100644
--- 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
@@ -2,12 +2,18 @@ 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::init();
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
+ .feature("nose", &[])
+ .feature("mouth", &[])
+ .feature("eyes", &[])
+ .feature("ears", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/features/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/features/mod.rs
index 5e4115390..aebae9b3b 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/features/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/features/mod.rs
@@ -2,12 +2,18 @@ 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::init();
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
+ .feature("nose", &[])
+ .feature("mouth", &[])
+ .feature("eyes", &[])
+ .feature("ears", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/features_empty/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/features_empty/mod.rs
index 81dffc1ee..d58c6a292 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/features_empty/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/features_empty/mod.rs
@@ -2,12 +2,18 @@ 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::init();
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
+ .feature("nose", &[])
+ .feature("mouth", &[])
+ .feature("eyes", &[])
+ .feature("ears", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/features_multiple_occurrences/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/features_multiple_occurrences/mod.rs
index db47f860d..4189be7ea 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/features_multiple_occurrences/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/features_multiple_occurrences/mod.rs
@@ -2,12 +2,18 @@ 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::init();
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
+ .feature("nose", &[])
+ .feature("mouth", &[])
+ .feature("eyes", &[])
+ .feature("ears", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/features_preserve/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/features_preserve/mod.rs
index ed99a3111..708fb4ddf 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/features_preserve/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/features_preserve/mod.rs
@@ -2,12 +2,18 @@ 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::init();
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
+ .feature("nose", &[])
+ .feature("mouth", &[])
+ .feature("eyes", &[])
+ .feature("ears", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/features_spaced_values/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/features_spaced_values/mod.rs
index 2ef212e59..4ee483110 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/features_spaced_values/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/features_spaced_values/mod.rs
@@ -2,12 +2,18 @@ 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::init();
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
+ .feature("nose", &[])
+ .feature("mouth", &[])
+ .feature("eyes", &[])
+ .feature("ears", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/features_unknown/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/features_unknown/mod.rs
index 7fd8d9529..552319402 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/features_unknown/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/features_unknown/mod.rs
@@ -2,12 +2,18 @@ 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::init();
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
+ .feature("nose", &[])
+ .feature("mouth", &[])
+ .feature("eyes", &[])
+ .feature("ears", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/features_unknown_no_features/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/features_unknown_no_features/mod.rs
index 9f59a0353..dff50a61f 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/features_unknown_no_features/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/features_unknown_no_features/mod.rs
@@ -2,12 +2,23 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/git/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/git/mod.rs
index bd82b3015..507fb417d 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/git/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/git/mod.rs
@@ -2,12 +2,12 @@ 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::init();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/git_branch/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/git_branch/mod.rs
index 051564566..8235a7c3c 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/git_branch/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/git_branch/mod.rs
@@ -2,12 +2,12 @@ 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::init();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/git_conflicts_namever/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/git_conflicts_namever/mod.rs
index f123298ae..86b268b59 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/git_conflicts_namever/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/git_conflicts_namever/mod.rs
@@ -2,12 +2,23 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/git_dev/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/git_dev/mod.rs
index 9e14a4007..96be4f46e 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/git_dev/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/git_dev/mod.rs
@@ -2,12 +2,12 @@ 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::init();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/git_inferred_name/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/git_inferred_name/mod.rs
index 52183adf4..4a3ded8c2 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/git_inferred_name/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/git_inferred_name/mod.rs
@@ -2,12 +2,12 @@ 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::init();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/git_inferred_name_multiple/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/git_inferred_name_multiple/mod.rs
index a708a8ae7..a915f3472 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/git_inferred_name_multiple/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/git_inferred_name_multiple/mod.rs
@@ -2,12 +2,12 @@ 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::init();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/git_multiple_names/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/git_multiple_names/mod.rs
index 39eb6e626..3ffe10714 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/git_multiple_names/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/git_multiple_names/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-package1", "my-package2"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/git_normalized_name/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/git_normalized_name/mod.rs
index 03d861856..dbad20105 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/git_normalized_name/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/git_normalized_name/mod.rs
@@ -2,12 +2,12 @@ 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::init();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/git_registry/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/git_registry/mod.rs
index 6bf6f8933..e44d71470 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/git_registry/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/git_registry/mod.rs
@@ -2,12 +2,25 @@ use cargo_test_support::compare::assert_ui;
use cargo_test_support::prelude::*;
use cargo_test_support::Project;
-use crate::cargo_add::init_alt_registry;
use cargo_test_support::curr_dir;
#[cargo_test]
fn case() {
- init_alt_registry();
+ cargo_test_support::registry::alt_init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("versioned-package", ver)
+ .alternative(true)
+ .publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/git_rev/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/git_rev/mod.rs
index 612607203..b8a669c7a 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/git_rev/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/git_rev/mod.rs
@@ -2,12 +2,12 @@ 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::init();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/git_tag/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/git_tag/mod.rs
index b355b1706..706fc9ab7 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/git_tag/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/git_tag/mod.rs
@@ -2,12 +2,12 @@ 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::init();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/infer_prerelease/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/infer_prerelease/mod.rs
index 94533f979..f2b49376a 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/infer_prerelease/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/infer_prerelease/mod.rs
@@ -2,12 +2,13 @@ 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::init();
+ cargo_test_support::registry::Package::new("prerelease_only", "0.2.0-alpha.1").publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/invalid_arg/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/invalid_arg/mod.rs
index 265a571bc..a4e4d268a 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/invalid_arg/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/invalid_arg/mod.rs
@@ -2,12 +2,23 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/invalid_git_external/stderr.log b/src/tools/cargo/tests/testsuite/cargo_add/invalid_git_external/stderr.log
deleted file mode 100644
index 18656300b..000000000
--- a/src/tools/cargo/tests/testsuite/cargo_add/invalid_git_external/stderr.log
+++ /dev/null
@@ -1,12 +0,0 @@
- Updating git repository `[ROOTURL]/case/does-not-exist/`
-...
-error: failed to load source for dependency `fake-git`
-
-Caused by:
- Unable to update [ROOTURL]/case/does-not-exist/
-
-Caused by:
- failed to clone into: [ROOT]/home/.cargo/git/db/does-not-exist-[..]
-
-Caused by:
-...
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/invalid_git_name/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/invalid_git_name/mod.rs
index 0aff8c090..2f407105d 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/invalid_git_name/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/invalid_git_name/mod.rs
@@ -2,12 +2,12 @@ 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::init();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/invalid_manifest/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/invalid_manifest/mod.rs
index e385cfc3f..4a2d01765 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/invalid_manifest/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/invalid_manifest/mod.rs
@@ -2,12 +2,23 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/invalid_name_external/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/invalid_name_external/mod.rs
index 16e041738..8cb9b5129 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/invalid_name_external/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/invalid_name_external/mod.rs
@@ -2,12 +2,12 @@ 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::init();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/invalid_path/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/invalid_path/mod.rs
index 0d26b552d..d8e6a34a6 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/invalid_path/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/invalid_path/mod.rs
@@ -2,12 +2,12 @@ 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::init();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/invalid_path_name/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/invalid_path_name/mod.rs
index 10d841475..aec088020 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/invalid_path_name/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/invalid_path_name/mod.rs
@@ -2,12 +2,24 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("cargo-list-test-fixture-dependency", ver)
+ .publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = project_root.join("primary");
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/invalid_path_self/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/invalid_path_self/mod.rs
index a64190f44..4bb32531b 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/invalid_path_self/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/invalid_path_self/mod.rs
@@ -2,12 +2,12 @@ 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::init();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/invalid_target_empty/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/invalid_target_empty/mod.rs
index da93c4eb8..43b3a4a79 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/invalid_target_empty/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/invalid_target_empty/mod.rs
@@ -2,12 +2,23 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/invalid_vers/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/invalid_vers/mod.rs
index c3b4d1f97..2ad903d1f 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/invalid_vers/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/invalid_vers/mod.rs
@@ -2,12 +2,23 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/list_features/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/list_features/mod.rs
index e1e1b212f..0dbf824d0 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/list_features/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/list_features/mod.rs
@@ -2,12 +2,18 @@ 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::init();
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
+ .feature("nose", &[])
+ .feature("mouth", &[])
+ .feature("eyes", &[])
+ .feature("ears", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/list_features_path/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/list_features_path/mod.rs
index 22733b883..e58de1c1d 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/list_features_path/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/list_features_path/mod.rs
@@ -2,12 +2,29 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
+ .feature("nose", &[])
+ .feature("mouth", &[])
+ .feature("eyes", &[])
+ .feature("ears", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = project_root.join("primary");
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/list_features_path_no_default/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/list_features_path_no_default/mod.rs
index f520b2aca..0aa20873e 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/list_features_path_no_default/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/list_features_path_no_default/mod.rs
@@ -2,12 +2,29 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
+ .feature("nose", &[])
+ .feature("mouth", &[])
+ .feature("eyes", &[])
+ .feature("ears", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = project_root.join("primary");
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/locked_changed/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/locked_changed/mod.rs
index 9e3e57fe5..5de047f57 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/locked_changed/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/locked_changed/mod.rs
@@ -2,12 +2,23 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/locked_unchanged/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/locked_unchanged/mod.rs
index aba9918f7..613d8c863 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/locked_unchanged/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/locked_unchanged/mod.rs
@@ -2,12 +2,23 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/lockfile_updated/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/lockfile_updated/mod.rs
index 33889dffa..4e99a18ef 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/lockfile_updated/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/lockfile_updated/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-package", "unrelateed-crate"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/manifest_path_package/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/manifest_path_package/mod.rs
index 008c2d33d..768cdb3a3 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/manifest_path_package/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/manifest_path_package/mod.rs
@@ -2,12 +2,24 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("cargo-list-test-fixture-dependency", ver)
+ .publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/mod.rs
index cd7e94e09..be7a1546b 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/mod.rs
@@ -1,6 +1,7 @@
mod add_basic;
mod add_multiple;
mod add_normalized_name_external;
+mod add_toolchain;
mod build;
mod build_prefer_existing_version;
mod change_rename_target;
@@ -36,7 +37,6 @@ mod git_rev;
mod git_tag;
mod infer_prerelease;
mod invalid_arg;
-mod invalid_git_external;
mod invalid_git_name;
mod invalid_key_inherit_dependency;
mod invalid_key_overwrite_inherit_dependency;
@@ -96,6 +96,7 @@ mod path_dev;
mod path_inferred_name;
mod path_inferred_name_conflicts_full_feature;
mod path_normalized_name;
+mod preserve_features_table;
mod preserve_sorted;
mod preserve_unsorted;
mod quiet;
@@ -114,95 +115,3 @@ mod vers;
mod workspace_name;
mod workspace_path;
mod workspace_path_dev;
-
-fn init_registry() {
- cargo_test_support::registry::init();
- add_registry_packages(false);
-}
-
-fn init_alt_registry() {
- cargo_test_support::registry::alt_init();
- add_registry_packages(true);
-}
-
-fn add_registry_packages(alt: bool) {
- for name in [
- "my-package",
- "my-package1",
- "my-package2",
- "my-dev-package1",
- "my-dev-package2",
- "my-build-package1",
- "my-build-package2",
- "toml",
- "versioned-package",
- "cargo-list-test-fixture-dependency",
- "unrelateed-crate",
- ] {
- cargo_test_support::registry::Package::new(name, "0.1.1+my-package")
- .alternative(alt)
- .publish();
- cargo_test_support::registry::Package::new(name, "0.2.0+my-package")
- .alternative(alt)
- .publish();
- cargo_test_support::registry::Package::new(name, "0.2.3+my-package")
- .alternative(alt)
- .publish();
- cargo_test_support::registry::Package::new(name, "0.4.1+my-package")
- .alternative(alt)
- .publish();
- cargo_test_support::registry::Package::new(name, "20.0.0+my-package")
- .alternative(alt)
- .publish();
- cargo_test_support::registry::Package::new(name, "99999.0.0+my-package")
- .alternative(alt)
- .publish();
- cargo_test_support::registry::Package::new(name, "99999.0.0-alpha.1+my-package")
- .alternative(alt)
- .publish();
- }
-
- cargo_test_support::registry::Package::new("prerelease_only", "0.2.0-alpha.1")
- .alternative(alt)
- .publish();
- cargo_test_support::registry::Package::new("test_breaking", "0.2.0")
- .alternative(alt)
- .publish();
- cargo_test_support::registry::Package::new("test_nonbreaking", "0.1.1")
- .alternative(alt)
- .publish();
- cargo_test_support::registry::Package::new("test_cyclic_features", "0.1.1")
- .alternative(alt)
- .feature("default", &["feature-one", "feature-two"])
- .feature("feature-one", &["feature-two"])
- .feature("feature-two", &["feature-one"])
- .publish();
-
- // Normalization
- cargo_test_support::registry::Package::new("linked-hash-map", "0.5.4")
- .alternative(alt)
- .feature("clippy", &[])
- .feature("heapsize", &[])
- .feature("heapsize_impl", &[])
- .feature("nightly", &[])
- .feature("serde", &[])
- .feature("serde_impl", &[])
- .feature("serde_test", &[])
- .publish();
- cargo_test_support::registry::Package::new("inflector", "0.11.4")
- .alternative(alt)
- .feature("default", &["heavyweight", "lazy_static", "regex"])
- .feature("heavyweight", &[])
- .feature("lazy_static", &[])
- .feature("regex", &[])
- .feature("unstable", &[])
- .publish();
-
- cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
- .alternative(alt)
- .feature("nose", &[])
- .feature("mouth", &[])
- .feature("eyes", &[])
- .feature("ears", &[])
- .publish();
-}
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/multiple_conflicts_with_features/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/multiple_conflicts_with_features/mod.rs
index 10f824484..3cdad0e72 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/multiple_conflicts_with_features/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/multiple_conflicts_with_features/mod.rs
@@ -2,12 +2,29 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package1", ver).publish();
+ }
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
+ .feature("nose", &[])
+ .feature("mouth", &[])
+ .feature("eyes", &[])
+ .feature("ears", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/multiple_conflicts_with_rename/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/multiple_conflicts_with_rename/mod.rs
index 293ed3eea..9a94dcffa 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/multiple_conflicts_with_rename/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/multiple_conflicts_with_rename/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-package1", "my-package2"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/namever/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/namever/mod.rs
index 90fda1a9f..063072c79 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/namever/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/namever/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-package", "my-package1", "my-package2"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/no_args/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/no_args/mod.rs
index 7eca17b56..aca1e5422 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/no_args/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/no_args/mod.rs
@@ -2,12 +2,12 @@ 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::init();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/no_default_features/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/no_default_features/mod.rs
index e72ca3be2..8a5d41c8d 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/no_default_features/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/no_default_features/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-package1", "my-package2"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/no_optional/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/no_optional/mod.rs
index fdb983b21..9145528bf 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/no_optional/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/no_optional/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-package1", "my-package2"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/offline_empty_cache/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/offline_empty_cache/mod.rs
index ae7485979..055b6a8a2 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/offline_empty_cache/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/offline_empty_cache/mod.rs
@@ -2,12 +2,23 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/optional/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/optional/mod.rs
index 94d1cbf34..408a46ed3 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/optional/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/optional/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-package1", "my-package2"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_default_features/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_default_features/mod.rs
index 88bdd8065..9d313b9d9 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_default_features/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_default_features/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-package1", "my-package2"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_default_features_with_no_default_features/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_default_features_with_no_default_features/mod.rs
index e72ca3be2..8a5d41c8d 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_default_features_with_no_default_features/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_default_features_with_no_default_features/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-package1", "my-package2"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_features/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_features/mod.rs
index 0b2ab18b8..da55fced2 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_features/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_features/mod.rs
@@ -2,12 +2,18 @@ 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::init();
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
+ .feature("nose", &[])
+ .feature("mouth", &[])
+ .feature("eyes", &[])
+ .feature("ears", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_git_with_path/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_git_with_path/mod.rs
index ab89e3a6d..fd63cc709 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_git_with_path/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_git_with_path/mod.rs
@@ -2,12 +2,24 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("cargo-list-test-fixture-dependency", ver)
+ .publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = project_root.join("primary");
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_inherit_features_noop/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_inherit_features_noop/mod.rs
index 161783282..2b9550ce0 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_inherit_features_noop/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_inherit_features_noop/mod.rs
@@ -6,6 +6,8 @@ use cargo_test_support::curr_dir;
#[cargo_test]
fn case() {
+ cargo_test_support::registry::init();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_inherit_noop/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_inherit_noop/mod.rs
index 065fb4f93..2b9550ce0 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_inherit_noop/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_inherit_noop/mod.rs
@@ -2,12 +2,12 @@ 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::init();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_inherit_optional_noop/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_inherit_optional_noop/mod.rs
index 065fb4f93..2b9550ce0 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_inherit_optional_noop/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_inherit_optional_noop/mod.rs
@@ -2,12 +2,12 @@ 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::init();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_inline_features/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_inline_features/mod.rs
index 356b4d788..52ad6968a 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_inline_features/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_inline_features/mod.rs
@@ -2,12 +2,29 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("unrelateed-crate", ver).publish();
+ }
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
+ .feature("nose", &[])
+ .feature("mouth", &[])
+ .feature("eyes", &[])
+ .feature("ears", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_name_dev_noop/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_name_dev_noop/mod.rs
index b418c7809..ea37368d5 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_name_dev_noop/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_name_dev_noop/mod.rs
@@ -2,12 +2,19 @@ use cargo_test_support::compare::assert_ui;
use cargo_test_support::prelude::*;
use cargo_test_support::Project;
-use crate::cargo_add::init_alt_registry;
use cargo_test_support::curr_dir;
#[cargo_test]
fn case() {
- init_alt_registry();
+ cargo_test_support::registry::alt_init();
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
+ .alternative(true)
+ .feature("nose", &[])
+ .feature("mouth", &[])
+ .feature("eyes", &[])
+ .feature("ears", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_name_noop/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_name_noop/mod.rs
index 193c5880b..120be4429 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_name_noop/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_name_noop/mod.rs
@@ -2,12 +2,19 @@ use cargo_test_support::compare::assert_ui;
use cargo_test_support::prelude::*;
use cargo_test_support::Project;
-use crate::cargo_add::init_alt_registry;
use cargo_test_support::curr_dir;
#[cargo_test]
fn case() {
- init_alt_registry();
+ cargo_test_support::registry::alt_init();
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
+ .alternative(true)
+ .feature("nose", &[])
+ .feature("mouth", &[])
+ .feature("eyes", &[])
+ .feature("ears", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_no_default_features/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_no_default_features/mod.rs
index e72ca3be2..8a5d41c8d 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_no_default_features/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_no_default_features/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-package1", "my-package2"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_no_default_features_with_default_features/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_no_default_features_with_default_features/mod.rs
index 88bdd8065..9d313b9d9 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_no_default_features_with_default_features/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_no_default_features_with_default_features/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-package1", "my-package2"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_no_optional/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_no_optional/mod.rs
index fdb983b21..9145528bf 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_no_optional/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_no_optional/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-package1", "my-package2"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_no_optional_with_optional/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_no_optional_with_optional/mod.rs
index 94d1cbf34..408a46ed3 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_no_optional_with_optional/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_no_optional_with_optional/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-package1", "my-package2"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_optional/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_optional/mod.rs
index 94d1cbf34..408a46ed3 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_optional/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_optional/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-package1", "my-package2"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_optional_with_no_optional/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_optional_with_no_optional/mod.rs
index c34c293f9..3090a7527 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_optional_with_no_optional/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_optional_with_no_optional/mod.rs
@@ -2,12 +2,29 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package2", ver).publish();
+ }
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
+ .feature("nose", &[])
+ .feature("mouth", &[])
+ .feature("eyes", &[])
+ .feature("ears", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_path_noop/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_path_noop/mod.rs
index f04405a34..fc057d852 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_path_noop/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_path_noop/mod.rs
@@ -2,12 +2,19 @@ use cargo_test_support::compare::assert_ui;
use cargo_test_support::prelude::*;
use cargo_test_support::Project;
-use crate::cargo_add::init_alt_registry;
use cargo_test_support::curr_dir;
#[cargo_test]
fn case() {
- init_alt_registry();
+ cargo_test_support::registry::alt_init();
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
+ .alternative(true)
+ .feature("nose", &[])
+ .feature("mouth", &[])
+ .feature("eyes", &[])
+ .feature("ears", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_path_with_version/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_path_with_version/mod.rs
index 32674e23d..bb93cfa15 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_path_with_version/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_path_with_version/mod.rs
@@ -2,12 +2,24 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("cargo-list-test-fixture-dependency", ver)
+ .publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = project_root.join("primary");
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_preserves_inline_table/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_preserves_inline_table/mod.rs
index 0b2ab18b8..da55fced2 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_preserves_inline_table/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_preserves_inline_table/mod.rs
@@ -2,12 +2,18 @@ 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::init();
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
+ .feature("nose", &[])
+ .feature("mouth", &[])
+ .feature("eyes", &[])
+ .feature("ears", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_rename_with_no_rename/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_rename_with_no_rename/mod.rs
index a006c95fd..ea49a07c1 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_rename_with_no_rename/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_rename_with_no_rename/mod.rs
@@ -2,12 +2,23 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("versioned-package", ver).publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_rename_with_rename/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_rename_with_rename/mod.rs
index e14282bc1..af96caef5 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_rename_with_rename/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_rename_with_rename/mod.rs
@@ -2,12 +2,23 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("versioned-package", ver).publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_rename_with_rename_noop/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_rename_with_rename_noop/mod.rs
index c0ca2e552..734d0b99a 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_rename_with_rename_noop/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_rename_with_rename_noop/mod.rs
@@ -2,12 +2,23 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("versioned-package", ver).publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_version_with_git/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_version_with_git/mod.rs
index ce7a0acb0..fcf0aa5e6 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_version_with_git/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_version_with_git/mod.rs
@@ -2,12 +2,23 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("versioned-package", ver).publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_version_with_path/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_version_with_path/mod.rs
index ab89e3a6d..fd63cc709 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_version_with_path/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_version_with_path/mod.rs
@@ -2,12 +2,24 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("cargo-list-test-fixture-dependency", ver)
+ .publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = project_root.join("primary");
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_with_rename/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_with_rename/mod.rs
index 05cc2d109..49a0ae0eb 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_with_rename/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_with_rename/mod.rs
@@ -2,12 +2,23 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("versioned-package", ver).publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_workspace_dep/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_workspace_dep/mod.rs
index 87ed58f7f..15cfa571c 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_workspace_dep/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_workspace_dep/mod.rs
@@ -2,12 +2,12 @@ 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::init();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_workspace_dep_features/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_workspace_dep_features/mod.rs
index 87ed58f7f..15cfa571c 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/overwrite_workspace_dep_features/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/overwrite_workspace_dep_features/mod.rs
@@ -2,12 +2,12 @@ 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::init();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/path/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/path/mod.rs
index ab89e3a6d..fd63cc709 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/path/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/path/mod.rs
@@ -2,12 +2,24 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("cargo-list-test-fixture-dependency", ver)
+ .publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = project_root.join("primary");
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/path_dev/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/path_dev/mod.rs
index 4ae04c70a..478e602a2 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/path_dev/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/path_dev/mod.rs
@@ -2,12 +2,24 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("cargo-list-test-fixture-dependency", ver)
+ .publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = project_root.join("primary");
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/path_inferred_name/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/path_inferred_name/mod.rs
index ab89e3a6d..fd63cc709 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/path_inferred_name/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/path_inferred_name/mod.rs
@@ -2,12 +2,24 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("cargo-list-test-fixture-dependency", ver)
+ .publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = project_root.join("primary");
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/path_inferred_name_conflicts_full_feature/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/path_inferred_name_conflicts_full_feature/mod.rs
index eadd096aa..17c328ea6 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/path_inferred_name_conflicts_full_feature/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/path_inferred_name_conflicts_full_feature/mod.rs
@@ -2,12 +2,12 @@ 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::init();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = project_root.join("primary");
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/path_normalized_name/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/path_normalized_name/mod.rs
index 754f2783f..8ae8a4e7d 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/path_normalized_name/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/path_normalized_name/mod.rs
@@ -2,12 +2,24 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("cargo-list-test-fixture-dependency", ver)
+ .publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = project_root.join("primary");
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/in/Cargo.toml
new file mode 100644
index 000000000..d32f5eb82
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/in/Cargo.toml
@@ -0,0 +1,21 @@
+[package]
+name = "xxx"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+your-face = { version = "99999.0.0", optional = true }
+
+[features]
+default = [
+ "a",
+ "b",
+ "c",
+]
+a = [
+ "your-face?/nose", # but not the mouth and nose
+]
+b = []
+c = []
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/in/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/in/src/lib.rs
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/in/src/lib.rs
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/mod.rs
new file mode 100644
index 000000000..1998fa742
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/mod.rs
@@ -0,0 +1,31 @@
+use cargo_test_support::compare::assert_ui;
+use cargo_test_support::prelude::*;
+use cargo_test_support::Project;
+
+use cargo_test_support::curr_dir;
+
+#[cargo_test]
+fn case() {
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
+ .feature("nose", &[])
+ .feature("mouth", &[])
+ .feature("eyes", &[])
+ .feature("ears", &[])
+ .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("add")
+ .arg_line("your-face --no-optional")
+ .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_add/preserve_features_table/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/out/Cargo.toml
new file mode 100644
index 000000000..39acd1016
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/out/Cargo.toml
@@ -0,0 +1,21 @@
+[package]
+name = "xxx"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+your-face = { version = "99999.0.0" }
+
+[features]
+default = [
+ "a",
+ "b",
+ "c",
+]
+a = [
+ "your-face/nose", # but not the mouth and nose
+]
+b = []
+c = []
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/stderr.log b/src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/stderr.log
new file mode 100644
index 000000000..796b9601b
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/stderr.log
@@ -0,0 +1,7 @@
+ Updating `dummy-registry` index
+ Adding your-face v99999.0.0 to dependencies.
+ Features:
+ - ears
+ - eyes
+ - mouth
+ - nose
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/stdout.log b/src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/stdout.log
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_add/preserve_features_table/stdout.log
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/preserve_sorted/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/preserve_sorted/mod.rs
index 4dfb06ed1..aef0d3d2f 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/preserve_sorted/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/preserve_sorted/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-package", "versioned-package", "toml"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/preserve_unsorted/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/preserve_unsorted/mod.rs
index 4dfb06ed1..aef0d3d2f 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/preserve_unsorted/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/preserve_unsorted/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-package", "versioned-package", "toml"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/quiet/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/quiet/mod.rs
index 357843901..1a02b0802 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/quiet/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/quiet/mod.rs
@@ -2,12 +2,18 @@ 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::init();
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
+ .feature("nose", &[])
+ .feature("mouth", &[])
+ .feature("eyes", &[])
+ .feature("ears", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/registry/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/registry/mod.rs
index d5ba9ef28..d0d937815 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/registry/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/registry/mod.rs
@@ -2,12 +2,27 @@ use cargo_test_support::compare::assert_ui;
use cargo_test_support::prelude::*;
use cargo_test_support::Project;
-use crate::cargo_add::init_alt_registry;
use cargo_test_support::curr_dir;
#[cargo_test]
fn case() {
- init_alt_registry();
+ cargo_test_support::registry::alt_init();
+ for name in ["my-package1", "my-package2"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver)
+ .alternative(true)
+ .publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rename/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/rename/mod.rs
index 3fefcccf3..28c92d770 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/rename/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/rename/mod.rs
@@ -2,12 +2,23 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/require_weak/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/require_weak/mod.rs
index d99e4482a..1998fa742 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/require_weak/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/require_weak/mod.rs
@@ -2,12 +2,18 @@ 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::init();
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
+ .feature("nose", &[])
+ .feature("mouth", &[])
+ .feature("eyes", &[])
+ .feature("ears", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
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
index 9aa11eaac..a382d95f1 100644
--- 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
@@ -2,13 +2,11 @@ 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::init();
cargo_test_support::registry::Package::new("rust-version-user", "0.1.0")
.rust_version("1.66")
.publish();
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
index 6baad0e05..31fb57786 100644
--- 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
@@ -2,13 +2,11 @@ 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::init();
cargo_test_support::registry::Package::new("rust-version-user", "0.1.0")
.rust_version("1.66")
.publish();
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
index 60e38960f..7a42c566e 100644
--- 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
@@ -2,13 +2,11 @@ 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::init();
cargo_test_support::registry::Package::new("rust-version-user", "0.1.0")
.rust_version("1.66")
.publish();
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
index 60e38960f..7a42c566e 100644
--- 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
@@ -2,13 +2,11 @@ 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::init();
cargo_test_support::registry::Package::new("rust-version-user", "0.1.0")
.rust_version("1.66")
.publish();
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/sorted_table_with_dotted_item/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/sorted_table_with_dotted_item/mod.rs
index 55e4c2281..46e8708a1 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/sorted_table_with_dotted_item/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/sorted_table_with_dotted_item/mod.rs
@@ -2,12 +2,30 @@ 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::init();
+ for name in [
+ "unrelateed-crate",
+ "versioned-package",
+ "toml",
+ "my-build-package1",
+ ] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/target/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/target/mod.rs
index e263bad36..b47874949 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/target/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/target/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-package1", "my-package2"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/target_cfg/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/target_cfg/mod.rs
index 43efe8e8d..0478ece76 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/target_cfg/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/target_cfg/mod.rs
@@ -2,12 +2,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();
+ cargo_test_support::registry::init();
+ for name in ["my-package1", "my-package2"] {
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new(name, ver).publish();
+ }
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/vers/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/vers/mod.rs
index fb78739e9..ee7dab2d1 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/vers/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/vers/mod.rs
@@ -2,12 +2,23 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/workspace_name/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/workspace_name/mod.rs
index ccaf850f9..2ab0807de 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/workspace_name/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/workspace_name/mod.rs
@@ -2,12 +2,24 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("cargo-list-test-fixture-dependency", ver)
+ .publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = project_root.join("primary");
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/workspace_path/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/workspace_path/mod.rs
index ab89e3a6d..fd63cc709 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/workspace_path/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/workspace_path/mod.rs
@@ -2,12 +2,24 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("cargo-list-test-fixture-dependency", ver)
+ .publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = project_root.join("primary");
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/workspace_path_dev/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/workspace_path_dev/mod.rs
index 4ae04c70a..478e602a2 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/workspace_path_dev/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/workspace_path_dev/mod.rs
@@ -2,12 +2,24 @@ 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::init();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("cargo-list-test-fixture-dependency", ver)
+ .publish();
+ }
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = project_root.join("primary");
diff --git a/src/tools/cargo/tests/testsuite/cargo_features.rs b/src/tools/cargo/tests/testsuite/cargo_features.rs
index 6e5531431..ed5f53a1e 100644
--- a/src/tools/cargo/tests/testsuite/cargo_features.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_features.rs
@@ -295,6 +295,7 @@ fn allow_features_to_rustc() {
.file(
"src/lib.rs",
r#"
+ #![allow(internal_features)]
#![feature(test_2018_feature)]
"#,
)
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/in/Cargo.toml
new file mode 100644
index 000000000..55ee0423c
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/in/Cargo.toml
@@ -0,0 +1,6 @@
+[workspace]
+resolver = "2"
+members = ["crates/*"]
+
+[workspace.lints.rust]
+unsafe_code = "forbid"
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/in/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/in/src/lib.rs
new file mode 100644
index 000000000..7d12d9af8
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/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_lints/mod.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/mod.rs
new file mode 100644
index 000000000..0b7697d20
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/mod.rs
@@ -0,0 +1,24 @@
+use cargo_test_support::compare::assert_ui;
+use cargo_test_support::curr_dir;
+use cargo_test_support::CargoCommand;
+use cargo_test_support::ChannelChanger;
+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", "-Zlints"])
+ .current_dir(cwd)
+ .masquerade_as_nightly_cargo(&["lints"])
+ .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_lints/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/out/Cargo.toml
new file mode 100644
index 000000000..55ee0423c
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/out/Cargo.toml
@@ -0,0 +1,6 @@
+[workspace]
+resolver = "2"
+members = ["crates/*"]
+
+[workspace.lints.rust]
+unsafe_code = "forbid"
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/out/crates/foo/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/out/crates/foo/Cargo.toml
new file mode 100644
index 000000000..0f3fe5d94
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/out/crates/foo/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "foo"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+
+[lints]
+workspace = true
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/out/crates/foo/src/main.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/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_lints/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_lints/out/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/out/src/lib.rs
new file mode 100644
index 000000000..7d12d9af8
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/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_lints/stderr.log b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/stderr.log
new file mode 100644
index 000000000..90150cdf5
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/stderr.log
@@ -0,0 +1 @@
+ Created binary (application) `crates/foo` package
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/stdout.log b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/stdout.log
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_lints/stdout.log
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
index b7a2e9036..cef4dd48b 100644
--- 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
@@ -1,4 +1,5 @@
[workspace]
+resolver = "2"
members = [
"crates/*",
]
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
index b7a2e9036..cef4dd48b 100644
--- 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
@@ -1,4 +1,5 @@
[workspace]
+resolver = "2"
members = [
"crates/*",
]
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
index b7a2e9036..cef4dd48b 100644
--- 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
@@ -1,4 +1,5 @@
[workspace]
+resolver = "2"
members = [
"crates/*",
]
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
index b7a2e9036..cef4dd48b 100644
--- 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
@@ -1,4 +1,5 @@
[workspace]
+resolver = "2"
members = [
"crates/*",
]
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/mod.rs b/src/tools/cargo/tests/testsuite/cargo_new/mod.rs
index 762a70b34..e895cf883 100644
--- a/src/tools/cargo/tests/testsuite/cargo_new/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_new/mod.rs
@@ -1,3 +1,4 @@
+mod inherit_workspace_lints;
mod inherit_workspace_package_table;
mod inherit_workspace_package_table_with_edition;
mod inherit_workspace_package_table_with_registry;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/avoid_empty_tables/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/avoid_empty_tables/mod.rs
index 59a2333d6..17bc3f949 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/avoid_empty_tables/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/avoid_empty_tables/mod.rs
@@ -3,11 +3,21 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/build/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/build/mod.rs
index f4c9dcb94..72ce478b9 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/build/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/build/mod.rs
@@ -3,11 +3,21 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/dev/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/dev/mod.rs
index 7d61fa954..d9cbdf1a7 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/dev/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/dev/mod.rs
@@ -3,11 +3,21 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/dry_run/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/dry_run/mod.rs
index dca189315..2e097135d 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/dry_run/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/dry_run/mod.rs
@@ -3,11 +3,21 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/gc_patch/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/gc_patch/mod.rs
index 2c1d592fb..ec521a5bb 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/gc_patch/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/gc_patch/mod.rs
@@ -5,11 +5,9 @@ use cargo_test_support::git;
use cargo_test_support::project;
use cargo_test_support::CargoCommand;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
let git_project1 = git::new("bar1", |project| {
project
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/gc_profile/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/gc_profile/mod.rs
index 7047c92e2..98b99bec3 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/gc_profile/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/gc_profile/mod.rs
@@ -3,11 +3,22 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.2.3+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/gc_replace/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/gc_replace/mod.rs
index 717adef3e..cbcf5bc07 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/gc_replace/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/gc_replace/mod.rs
@@ -3,11 +3,22 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.2.3+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_arg/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_arg/mod.rs
index eac3c8b46..97d5c8625 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_arg/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_arg/mod.rs
@@ -3,11 +3,21 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_dep/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_dep/mod.rs
index c4dbeae91..fb32a075f 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_dep/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_dep/mod.rs
@@ -3,11 +3,21 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_package/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_package/mod.rs
index bff09882e..d7f84c035 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_package/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_package/mod.rs
@@ -3,11 +3,23 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("dbus", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("ncurses", "20.0.0+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_package_multiple/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_package_multiple/mod.rs
index 5093d5d2d..d14179e0c 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_package_multiple/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_package_multiple/mod.rs
@@ -3,11 +3,23 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("dbus", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("ncurses", "20.0.0+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_section/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_section/mod.rs
index 80d42be1d..94d475059 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_section/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_section/mod.rs
@@ -3,11 +3,21 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_section_dep/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_section_dep/mod.rs
index 7be8fd628..c20cd94d2 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_section_dep/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_section_dep/mod.rs
@@ -3,11 +3,21 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_target/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_target/mod.rs
index 34deb6cb8..aba040a2b 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_target/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_target/mod.rs
@@ -3,11 +3,23 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("dbus", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("ncurses", "20.0.0+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_target_dep/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_target_dep/mod.rs
index e04418fa8..f187e609c 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_target_dep/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_target_dep/mod.rs
@@ -3,11 +3,23 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("dbus", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("ncurses", "20.0.0+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/mod.rs
index fd8b4a233..feb08cea4 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/mod.rs
@@ -28,61 +28,3 @@ mod update_lock_file;
mod workspace;
mod workspace_non_virtual;
mod workspace_preserved;
-
-fn init_registry() {
- cargo_test_support::registry::init();
- add_registry_packages(false);
-}
-
-fn add_registry_packages(alt: bool) {
- for name in [
- "clippy",
- "dbus",
- "docopt",
- "ncurses",
- "pad",
- "regex",
- "rustc-serialize",
- "toml",
- ] {
- cargo_test_support::registry::Package::new(name, "0.1.1+my-package")
- .alternative(alt)
- .publish();
- cargo_test_support::registry::Package::new(name, "0.2.0+my-package")
- .alternative(alt)
- .publish();
- cargo_test_support::registry::Package::new(name, "0.2.3+my-package")
- .alternative(alt)
- .publish();
- cargo_test_support::registry::Package::new(name, "0.4.1+my-package")
- .alternative(alt)
- .publish();
- cargo_test_support::registry::Package::new(name, "0.6.2+my-package")
- .alternative(alt)
- .publish();
- cargo_test_support::registry::Package::new(name, "0.9.9+my-package")
- .alternative(alt)
- .publish();
- cargo_test_support::registry::Package::new(name, "1.0.90+my-package")
- .alternative(alt)
- .publish();
- cargo_test_support::registry::Package::new(name, "20.0.0+my-package")
- .alternative(alt)
- .publish();
- }
-
- for name in ["semver", "serde"] {
- cargo_test_support::registry::Package::new(name, "0.1.1")
- .alternative(alt)
- .feature("std", &[])
- .publish();
- cargo_test_support::registry::Package::new(name, "0.9.0")
- .alternative(alt)
- .feature("std", &[])
- .publish();
- cargo_test_support::registry::Package::new(name, "1.0.90")
- .alternative(alt)
- .feature("std", &[])
- .publish();
- }
-}
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/multiple_deps/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/multiple_deps/mod.rs
index 35922b738..d0af30a30 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/multiple_deps/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/multiple_deps/mod.rs
@@ -3,11 +3,21 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/multiple_dev/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/multiple_dev/mod.rs
index 5eac7e2f8..7ec2bd0b7 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/multiple_dev/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/multiple_dev/mod.rs
@@ -3,11 +3,21 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/no_arg/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/no_arg/mod.rs
index d0c66f9b0..f9e0e5548 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/no_arg/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/no_arg/mod.rs
@@ -3,11 +3,21 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/offline/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/offline/mod.rs
index d03463927..e227eb095 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/offline/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/offline/mod.rs
@@ -3,11 +3,21 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature/mod.rs
index cae736b34..ce8fcf712 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature/mod.rs
@@ -3,11 +3,21 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/optional_feature/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/optional_feature/mod.rs
index af54226bb..9ab3c4c24 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/optional_feature/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/optional_feature/mod.rs
@@ -3,11 +3,21 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/package/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/package/mod.rs
index 2714f3197..73d01b89d 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/package/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/package/mod.rs
@@ -3,11 +3,23 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("dbus", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("ncurses", "20.0.0+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/remove_basic/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/remove_basic/mod.rs
index 53381e6bc..7c92026a5 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/remove_basic/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/remove_basic/mod.rs
@@ -3,11 +3,21 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/target/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/target/mod.rs
index 1447c753d..6f6fc5c61 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/target/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/target/mod.rs
@@ -3,11 +3,23 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("dbus", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("ncurses", "20.0.0+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/target_build/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/target_build/mod.rs
index 11afbbf8f..7adffa229 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/target_build/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/target_build/mod.rs
@@ -3,11 +3,23 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("dbus", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("ncurses", "20.0.0+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/target_dev/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/target_dev/mod.rs
index d303c2b85..005eb7871 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/target_dev/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/target_dev/mod.rs
@@ -3,11 +3,23 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("dbus", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("ncurses", "20.0.0+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/update_lock_file/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/update_lock_file/mod.rs
index be5bc87f5..00e7964e4 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/update_lock_file/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/update_lock_file/mod.rs
@@ -3,11 +3,21 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.1+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/workspace/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/workspace/mod.rs
index 225fbec00..5274b07d7 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/workspace/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/workspace/mod.rs
@@ -3,11 +3,21 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/workspace_non_virtual/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/workspace_non_virtual/mod.rs
index 225fbec00..5274b07d7 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/workspace_non_virtual/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/workspace_non_virtual/mod.rs
@@ -3,11 +3,21 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/workspace_preserved/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/workspace_preserved/mod.rs
index 225fbec00..5274b07d7 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/workspace_preserved/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/workspace_preserved/mod.rs
@@ -3,11 +3,21 @@ use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
-use crate::cargo_remove::init_registry;
-
#[cargo_test]
fn case() {
- init_registry();
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;
diff --git a/src/tools/cargo/tests/testsuite/config.rs b/src/tools/cargo/tests/testsuite/config.rs
index b0f9d167b..5d4163818 100644
--- a/src/tools/cargo/tests/testsuite/config.rs
+++ b/src/tools/cargo/tests/testsuite/config.rs
@@ -1,7 +1,7 @@
//! Tests for config settings.
use cargo::core::{PackageIdSpec, Shell};
-use cargo::util::config::{self, Config, Definition, SslVersionConfig, StringList};
+use cargo::util::config::{self, Config, Definition, JobsConfig, SslVersionConfig, StringList};
use cargo::util::interning::InternedString;
use cargo::util::toml::{self as cargo_toml, TomlDebugInfo, VecStringOrBool as VSOB};
use cargo::CargoResult;
@@ -1651,3 +1651,63 @@ fn debuginfo_parsing() {
.ends_with("could not load config key `profile.dev.debug`"));
}
}
+
+#[cargo_test]
+fn build_jobs_missing() {
+ write_config(
+ "\
+[build]
+",
+ );
+
+ let config = new_config();
+
+ assert!(config
+ .get::<Option<JobsConfig>>("build.jobs")
+ .unwrap()
+ .is_none());
+}
+
+#[cargo_test]
+fn build_jobs_default() {
+ write_config(
+ "\
+[build]
+jobs = \"default\"
+",
+ );
+
+ let config = new_config();
+
+ let a = config
+ .get::<Option<JobsConfig>>("build.jobs")
+ .unwrap()
+ .unwrap();
+
+ match a {
+ JobsConfig::String(v) => assert_eq!(&v, "default"),
+ JobsConfig::Integer(_) => panic!("Did not except an integer."),
+ }
+}
+
+#[cargo_test]
+fn build_jobs_integer() {
+ write_config(
+ "\
+[build]
+jobs = 2
+",
+ );
+
+ let config = new_config();
+
+ let a = config
+ .get::<Option<JobsConfig>>("build.jobs")
+ .unwrap()
+ .unwrap();
+
+ match a {
+ JobsConfig::String(_) => panic!("Did not except an integer."),
+ JobsConfig::Integer(v) => assert_eq!(v, 2),
+ }
+}
diff --git a/src/tools/cargo/tests/testsuite/config_include.rs b/src/tools/cargo/tests/testsuite/config_include.rs
index ae568065a..057c583ae 100644
--- a/src/tools/cargo/tests/testsuite/config_include.rs
+++ b/src/tools/cargo/tests/testsuite/config_include.rs
@@ -6,9 +6,9 @@ use cargo_test_support::{no_such_file_err_msg, project};
#[cargo_test]
fn gated() {
// Requires -Z flag.
- write_config("include='other'");
+ write_config("include='other.toml'");
write_config_at(
- ".cargo/other",
+ ".cargo/other.toml",
"
othervalue = 1
",
@@ -25,13 +25,13 @@ fn simple() {
write_config_at(
".cargo/config",
"
- include = 'other'
+ include = 'other.toml'
key1 = 1
key2 = 2
",
);
write_config_at(
- ".cargo/other",
+ ".cargo/other.toml",
"
key2 = 3
key3 = 4
@@ -84,39 +84,63 @@ fn works_with_cli() {
}
#[cargo_test]
-fn left_to_right() {
- // How it merges multiple includes.
+fn left_to_right_bottom_to_top() {
+ // How it merges multiple nested includes.
write_config_at(
".cargo/config",
"
- include = ['one', 'two']
- primary = 1
+ include = ['left-middle.toml', 'right-middle.toml']
+ top = 1
+ ",
+ );
+ write_config_at(
+ ".cargo/right-middle.toml",
+ "
+ include = 'right-bottom.toml'
+ top = 0
+ right-middle = 0
",
);
write_config_at(
- ".cargo/one",
+ ".cargo/right-bottom.toml",
"
- one = 1
- primary = 2
+ top = -1
+ right-middle = -1
+ right-bottom = -1
",
);
write_config_at(
- ".cargo/two",
+ ".cargo/left-middle.toml",
"
- two = 2
- primary = 3
+ include = 'left-bottom.toml'
+ top = -2
+ right-middle = -2
+ right-bottom = -2
+ left-middle = -2
+ ",
+ );
+ write_config_at(
+ ".cargo/left-bottom.toml",
+ "
+ top = -3
+ right-middle = -3
+ right-bottom = -3
+ left-middle = -3
+ left-bottom = -3
",
);
let config = ConfigBuilder::new().unstable_flag("config-include").build();
- assert_eq!(config.get::<i32>("primary").unwrap(), 1);
- assert_eq!(config.get::<i32>("one").unwrap(), 1);
- assert_eq!(config.get::<i32>("two").unwrap(), 2);
+ assert_eq!(config.get::<i32>("top").unwrap(), 1);
+ assert_eq!(config.get::<i32>("right-middle").unwrap(), 0);
+ assert_eq!(config.get::<i32>("right-bottom").unwrap(), -1);
+ assert_eq!(config.get::<i32>("left-middle").unwrap(), -2);
+ assert_eq!(config.get::<i32>("left-bottom").unwrap(), -3);
}
#[cargo_test]
fn missing_file() {
// Error when there's a missing file.
- write_config("include='missing'");
+ write_config("include='missing.toml'");
let config = ConfigBuilder::new()
.unstable_flag("config-include")
.build_err();
@@ -127,10 +151,10 @@ fn missing_file() {
could not load Cargo configuration
Caused by:
- failed to load config include `missing` from `[..]/.cargo/config`
+ failed to load config include `missing.toml` from `[..]/.cargo/config`
Caused by:
- failed to read configuration file `[..]/.cargo/missing`
+ failed to read configuration file `[..]/.cargo/missing.toml`
Caused by:
{}",
@@ -140,11 +164,29 @@ Caused by:
}
#[cargo_test]
+fn wrong_file_extension() {
+ // Error when it doesn't end with `.toml`.
+ write_config("include='config.png'");
+ let config = ConfigBuilder::new()
+ .unstable_flag("config-include")
+ .build_err();
+ assert_error(
+ config.unwrap_err(),
+ "\
+could not load Cargo configuration
+
+Caused by:
+ expected a config include path ending with `.toml`, but found `config.png` from `[..]/.cargo/config`
+",
+ );
+}
+
+#[cargo_test]
fn cycle() {
// Detects a cycle.
- write_config_at(".cargo/config", "include='one'");
- write_config_at(".cargo/one", "include='two'");
- write_config_at(".cargo/two", "include='config'");
+ write_config_at(".cargo/config.toml", "include='one.toml'");
+ write_config_at(".cargo/one.toml", "include='two.toml'");
+ write_config_at(".cargo/two.toml", "include='config.toml'");
let config = ConfigBuilder::new()
.unstable_flag("config-include")
.build_err();
@@ -154,16 +196,16 @@ fn cycle() {
could not load Cargo configuration
Caused by:
- failed to load config include `one` from `[..]/.cargo/config`
+ failed to load config include `one.toml` from `[..]/.cargo/config.toml`
Caused by:
- failed to load config include `two` from `[..]/.cargo/one`
+ failed to load config include `two.toml` from `[..]/.cargo/one.toml`
Caused by:
- failed to load config include `config` from `[..]/.cargo/two`
+ failed to load config include `config.toml` from `[..]/.cargo/two.toml`
Caused by:
- config `include` cycle detected with path `[..]/.cargo/config`",
+ config `include` cycle detected with path `[..]/.cargo/config.toml`",
);
}
@@ -178,10 +220,10 @@ fn cli_include() {
bar = 2
",
);
- write_config_at(".cargo/config-foo", "foo = 2");
+ write_config_at(".cargo/config-foo.toml", "foo = 2");
let config = ConfigBuilder::new()
.unstable_flag("config-include")
- .config_arg("include='.cargo/config-foo'")
+ .config_arg("include='.cargo/config-foo.toml'")
.build();
assert_eq!(config.get::<i32>("foo").unwrap(), 2);
assert_eq!(config.get::<i32>("bar").unwrap(), 2);
@@ -209,7 +251,7 @@ fn cli_include_failed() {
// Error message when CLI include fails to load.
let config = ConfigBuilder::new()
.unstable_flag("config-include")
- .config_arg("include='foobar'")
+ .config_arg("include='foobar.toml'")
.build_err();
assert_error(
config.unwrap_err(),
@@ -218,10 +260,10 @@ fn cli_include_failed() {
failed to load --config include
Caused by:
- failed to load config include `foobar` from `--config cli option`
+ failed to load config include `foobar.toml` from `--config cli option`
Caused by:
- failed to read configuration file `[..]/foobar`
+ failed to read configuration file `[..]/foobar.toml`
Caused by:
{}",
@@ -235,14 +277,14 @@ fn cli_merge_failed() {
// Error message when CLI include merge fails.
write_config("foo = ['a']");
write_config_at(
- ".cargo/other",
+ ".cargo/other.toml",
"
foo = 'b'
",
);
let config = ConfigBuilder::new()
.unstable_flag("config-include")
- .config_arg("include='.cargo/other'")
+ .config_arg("include='.cargo/other.toml'")
.build_err();
// Maybe this error message should mention it was from an include file?
assert_error(
@@ -251,7 +293,7 @@ fn cli_merge_failed() {
failed to merge --config key `foo` into `[..]/.cargo/config`
Caused by:
- failed to merge config value from `[..]/.cargo/other` into `[..]/.cargo/config`: \
+ failed to merge config value from `[..]/.cargo/other.toml` into `[..]/.cargo/config`: \
expected array, but found string",
);
}
diff --git a/src/tools/cargo/tests/testsuite/cross_compile.rs b/src/tools/cargo/tests/testsuite/cross_compile.rs
index cc9644550..1bc0c277d 100644
--- a/src/tools/cargo/tests/testsuite/cross_compile.rs
+++ b/src/tools/cargo/tests/testsuite/cross_compile.rs
@@ -398,7 +398,7 @@ fn linker() {
"\
[COMPILING] foo v0.5.0 ([CWD])
[RUNNING] `rustc --crate-name foo src/foo.rs [..]--crate-type bin \
- --emit=[..]link[..]-C debuginfo=2 \
+ --emit=[..]link[..]-C debuginfo=2 [..]\
-C metadata=[..] \
--out-dir [CWD]/target/{target}/debug/deps \
--target {target} \
diff --git a/src/tools/cargo/tests/testsuite/custom_target.rs b/src/tools/cargo/tests/testsuite/custom_target.rs
index b7ad4d835..491d3233c 100644
--- a/src/tools/cargo/tests/testsuite/custom_target.rs
+++ b/src/tools/cargo/tests/testsuite/custom_target.rs
@@ -4,6 +4,7 @@ use cargo_test_support::{basic_manifest, project};
use std::fs;
const MINIMAL_LIB: &str = r#"
+#![allow(internal_features)]
#![feature(no_core)]
#![feature(lang_items)]
#![no_core]
@@ -80,6 +81,7 @@ fn custom_target_dependency() {
.file(
"src/lib.rs",
r#"
+ #![allow(internal_features)]
#![feature(no_core)]
#![feature(lang_items)]
#![feature(auto_traits)]
diff --git a/src/tools/cargo/tests/testsuite/directory.rs b/src/tools/cargo/tests/testsuite/directory.rs
index 0e28de039..e72f1f07d 100644
--- a/src/tools/cargo/tests/testsuite/directory.rs
+++ b/src/tools/cargo/tests/testsuite/directory.rs
@@ -188,7 +188,9 @@ fn simple_install_fail() {
.with_status(101)
.with_stderr(
" Installing bar v0.1.0
-error: failed to compile `bar v0.1.0`, intermediate artifacts can be found at `[..]`
+error: failed to compile `bar v0.1.0`, intermediate artifacts can be found at `[..]`.
+To reuse those artifacts with a future compilation, set the environment variable \
+`CARGO_TARGET_DIR` to that path.
Caused by:
no matching package found
@@ -759,7 +761,9 @@ fn version_missing() {
.with_stderr(
"\
[INSTALLING] bar v0.1.0
-error: failed to compile [..]
+error: failed to compile [..], intermediate artifacts can be found at `[..]`.
+To reuse those artifacts with a future compilation, set the environment variable \
+`CARGO_TARGET_DIR` to that path.
Caused by:
failed to select a version for the requirement `foo = \"^2\"`
diff --git a/src/tools/cargo/tests/testsuite/doc.rs b/src/tools/cargo/tests/testsuite/doc.rs
index 739bcf376..481df8590 100644
--- a/src/tools/cargo/tests/testsuite/doc.rs
+++ b/src/tools/cargo/tests/testsuite/doc.rs
@@ -756,6 +756,7 @@ fn doc_target() {
.file(
"src/lib.rs",
r#"
+ #![allow(internal_features)]
#![feature(no_core, lang_items)]
#![no_core]
@@ -2041,7 +2042,7 @@ fn crate_versions_flag_is_overridden() {
asserts(output_documentation());
}
-#[cargo_test(nightly, reason = "-Zdoctest-in-workspace is unstable")]
+#[cargo_test]
fn doc_test_in_workspace() {
let p = project()
.file(
@@ -2087,8 +2088,7 @@ fn doc_test_in_workspace() {
",
)
.build();
- p.cargo("test -Zdoctest-in-workspace --doc -vv")
- .masquerade_as_nightly_cargo(&["doctest-in-workspace"])
+ p.cargo("test --doc -vv")
.with_stderr_contains("[DOCTEST] crate-a")
.with_stdout_contains(
"
@@ -2096,7 +2096,6 @@ running 1 test
test crate-a/src/lib.rs - (line 1) ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out[..]
-
",
)
.with_stderr_contains("[DOCTEST] crate-b")
@@ -2106,7 +2105,98 @@ running 1 test
test crate-b/src/lib.rs - (line 1) ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out[..]
+",
+ )
+ .run();
+}
+
+/// This is a test for <https://github.com/rust-lang/rust/issues/46372>.
+/// The `file!()` macro inside of an `include!()` should output
+/// workspace-relative paths, just like it does in other cases.
+#[cargo_test]
+fn doc_test_include_file() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [workspace]
+ members = [
+ "child",
+ ]
+ [package]
+ name = "root"
+ version = "0.1.0"
+ "#,
+ )
+ .file(
+ "src/lib.rs",
+ r#"
+ /// ```
+ /// assert_eq!("src/lib.rs", file!().replace("\\", "/"))
+ /// ```
+ pub mod included {
+ include!(concat!("../", file!(), ".included.rs"));
+ }
+ "#,
+ )
+ .file(
+ "src/lib.rs.included.rs",
+ r#"
+ /// ```
+ /// assert_eq!(1, 1)
+ /// ```
+ pub fn foo() {}
+ "#,
+ )
+ .file(
+ "child/Cargo.toml",
+ r#"
+ [package]
+ name = "child"
+ version = "0.1.0"
+ "#,
+ )
+ .file(
+ "child/src/lib.rs",
+ r#"
+ /// ```
+ /// assert_eq!("child/src/lib.rs", file!().replace("\\", "/"))
+ /// ```
+ pub mod included {
+ include!(concat!("../../", file!(), ".included.rs"));
+ }
+ "#,
+ )
+ .file(
+ "child/src/lib.rs.included.rs",
+ r#"
+ /// ```
+ /// assert_eq!(1, 1)
+ /// ```
+ pub fn foo() {}
+ "#,
+ )
+ .build();
+
+ p.cargo("test --workspace --doc -vv -- --test-threads=1")
+ .with_stderr_contains("[DOCTEST] child")
+ .with_stdout_contains(
+ "
+running 2 tests
+test child/src/../../child/src/lib.rs.included.rs - included::foo (line 2) ... ok
+test child/src/lib.rs - included (line 2) ... ok
+
+test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out[..]
+",
+ )
+ .with_stderr_contains("[DOCTEST] root")
+ .with_stdout_contains(
+ "
+running 2 tests
+test src/../src/lib.rs.included.rs - included::foo (line 2) ... ok
+test src/lib.rs - included (line 2) ... ok
+test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out[..]
",
)
.run();
diff --git a/src/tools/cargo/tests/testsuite/features.rs b/src/tools/cargo/tests/testsuite/features.rs
index 848e05677..557fab14a 100644
--- a/src/tools/cargo/tests/testsuite/features.rs
+++ b/src/tools/cargo/tests/testsuite/features.rs
@@ -1937,8 +1937,8 @@ fn nonexistent_required_features() {
}
#[cargo_test]
-fn invalid_feature_names_warning() {
- // Warnings for more restricted feature syntax.
+fn invalid_feature_names_error() {
+ // Errors for more restricted feature syntax.
let p = project()
.file(
"Cargo.toml",
@@ -1948,72 +1948,57 @@ fn invalid_feature_names_warning() {
version = "0.1.0"
[features]
- # Some valid, but unusual names, shouldn't warn.
- "c++17" = []
- "128bit" = []
- "_foo" = []
- "feat-name" = []
- "feat_name" = []
- "foo.bar" = []
-
- # Invalid names.
+ # Invalid start character.
"+foo" = []
- "-foo" = []
- ".foo" = []
- "foo:bar" = []
- "foo?" = []
- "?foo" = []
- "ⒶⒷⒸ" = []
- "a¼" = []
"#,
)
.file("src/lib.rs", "")
.build();
- // Unfortunately the warnings are duplicated due to the Summary being
- // loaded twice (once in the Workspace, and once in PackageRegistry) and
- // Cargo does not have a de-duplication system. This should probably be
- // OK, since I'm not expecting this to affect anyone.
p.cargo("check")
- .with_stderr("\
-[WARNING] invalid character `+` in feature `+foo` in package foo v0.1.0 ([ROOT]/foo), the first character must be a Unicode XID start character or digit (most letters or `_` or `0` to `9`)
-This was previously accepted but is being phased out; it will become a hard error in a future release.
-For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
-[WARNING] invalid character `-` in feature `-foo` in package foo v0.1.0 ([ROOT]/foo), the first character must be a Unicode XID start character or digit (most letters or `_` or `0` to `9`)
-This was previously accepted but is being phased out; it will become a hard error in a future release.
-For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
-[WARNING] invalid character `.` in feature `.foo` in package foo v0.1.0 ([ROOT]/foo), the first character must be a Unicode XID start character or digit (most letters or `_` or `0` to `9`)
-This was previously accepted but is being phased out; it will become a hard error in a future release.
-For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
-[WARNING] invalid character `?` in feature `?foo` in package foo v0.1.0 ([ROOT]/foo), the first character must be a Unicode XID start character or digit (most letters or `_` or `0` to `9`)
-This was previously accepted but is being phased out; it will become a hard error in a future release.
-For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
-[WARNING] invalid character `¼` in feature `a¼` in package foo v0.1.0 ([ROOT]/foo), characters must be Unicode XID characters, `+`, or `.` (numbers, `+`, `-`, `_`, `.`, or most letters)
-This was previously accepted but is being phased out; it will become a hard error in a future release.
-For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
-[WARNING] invalid character `:` in feature `foo:bar` in package foo v0.1.0 ([ROOT]/foo), characters must be Unicode XID characters, `+`, or `.` (numbers, `+`, `-`, `_`, `.`, or most letters)
-This was previously accepted but is being phased out; it will become a hard error in a future release.
-For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
-[WARNING] invalid character `?` in feature `foo?` in package foo v0.1.0 ([ROOT]/foo), characters must be Unicode XID characters, `+`, or `.` (numbers, `+`, `-`, `_`, `.`, or most letters)
-This was previously accepted but is being phased out; it will become a hard error in a future release.
-For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
-[WARNING] invalid character `Ⓐ` in feature `ⒶⒷⒸ` in package foo v0.1.0 ([ROOT]/foo), the first character must be a Unicode XID start character or digit (most letters or `_` or `0` to `9`)
-This was previously accepted but is being phased out; it will become a hard error in a future release.
-For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
-[WARNING] invalid character `Ⓑ` in feature `ⒶⒷⒸ` in package foo v0.1.0 ([ROOT]/foo), characters must be Unicode XID characters, `+`, or `.` (numbers, `+`, `-`, `_`, `.`, or most letters)
-This was previously accepted but is being phased out; it will become a hard error in a future release.
-For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
-[WARNING] invalid character `Ⓒ` in feature `ⒶⒷⒸ` in package foo v0.1.0 ([ROOT]/foo), characters must be Unicode XID characters, `+`, or `.` (numbers, `+`, `-`, `_`, `.`, or most letters)
-This was previously accepted but is being phased out; it will become a hard error in a future release.
-For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
-[CHECKING] foo v0.1.0 [..]
-[FINISHED] [..]
-")
+ .with_status(101)
+ .with_stderr(
+ "\
+error: failed to parse manifest at `[ROOT]/foo/Cargo.toml`
+
+Caused by:
+ invalid character `+` in feature `+foo` in package foo v0.1.0 ([ROOT]/foo), \
+ the first character must be a Unicode XID start character or digit \
+ (most letters or `_` or `0` to `9`)
+",
+ )
+ .run();
+
+ p.change_file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.1.0"
+
+ [features]
+ # Invalid continue character.
+ "a&b" = []
+ "#,
+ );
+
+ p.cargo("check")
+ .with_status(101)
+ .with_stderr(
+ "\
+error: failed to parse manifest at `[ROOT]/foo/Cargo.toml`
+
+Caused by:
+ invalid character `&` in feature `a&b` in package foo v0.1.0 ([ROOT]/foo), \
+ characters must be Unicode XID characters, `+`, or `.` \
+ (numbers, `+`, `-`, `_`, `.`, or most letters)
+",
+ )
.run();
}
#[cargo_test]
-fn invalid_feature_names_error() {
+fn invalid_feature_name_slash_error() {
// Errors for more restricted feature syntax.
let p = project()
.file(
diff --git a/src/tools/cargo/tests/testsuite/features2.rs b/src/tools/cargo/tests/testsuite/features2.rs
index 494c83f1e..68fecb863 100644
--- a/src/tools/cargo/tests/testsuite/features2.rs
+++ b/src/tools/cargo/tests/testsuite/features2.rs
@@ -1407,6 +1407,41 @@ workspace: [..]/foo/Cargo.toml
}
#[cargo_test]
+fn edition_2021_workspace_member() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [workspace]
+ members = ["a"]
+ "#,
+ )
+ .file(
+ "a/Cargo.toml",
+ r#"
+ [package]
+ name = "a"
+ version = "0.1.0"
+ edition = "2021"
+ "#,
+ )
+ .file("a/src/lib.rs", "")
+ .build();
+
+ p.cargo("check")
+ .with_stderr(
+ "\
+warning: some crates are on edition 2021 which defaults to `resolver = \"2\"`, but virtual workspaces default to `resolver = \"1\"`
+note: to keep the current resolver, specify `workspace.resolver = \"1\"` in the workspace root's manifest
+note: to use the edition 2021 resolver, specify `workspace.resolver = \"2\"` in the workspace root's manifest
+[CHECKING] a v0.1.0 [..]
+[FINISHED] [..]
+",
+ )
+ .run();
+}
+
+#[cargo_test]
fn resolver_ws_root_and_member() {
// Check when specified in both ws root and member.
let p = project()
diff --git a/src/tools/cargo/tests/testsuite/future_incompat_report.rs b/src/tools/cargo/tests/testsuite/future_incompat_report.rs
index 9f451a64c..4d2c66d17 100644
--- a/src/tools/cargo/tests/testsuite/future_incompat_report.rs
+++ b/src/tools/cargo/tests/testsuite/future_incompat_report.rs
@@ -164,7 +164,7 @@ fn test_multi_crate() {
second-dep = "*"
"#,
)
- .file("src/main.rs", "fn main() {}")
+ .file("src/lib.rs", "")
.build();
for command in &["build", "check", "rustc", "test"] {
diff --git a/src/tools/cargo/tests/testsuite/git.rs b/src/tools/cargo/tests/testsuite/git.rs
index 7c717e967..f60ee978a 100644
--- a/src/tools/cargo/tests/testsuite/git.rs
+++ b/src/tools/cargo/tests/testsuite/git.rs
@@ -3619,3 +3619,71 @@ fn cleans_temp_pack_files() {
p.cargo("generate-lockfile").run();
assert!(!tmp_path.exists());
}
+
+#[cargo_test]
+fn different_user_relative_submodules() {
+ let user1_git_project = git::new("user1/dep1", |project| {
+ project
+ .file("Cargo.toml", &basic_lib_manifest("dep1"))
+ .file("src/lib.rs", "")
+ });
+
+ let user2_git_project = git::new("user2/dep1", |project| {
+ project
+ .file("Cargo.toml", &basic_lib_manifest("dep1"))
+ .file("src/lib.rs", "")
+ });
+ let user2_git_project2 = git::new("user2/dep2", |project| {
+ project
+ .file("Cargo.toml", &basic_lib_manifest("dep1"))
+ .file("src/lib.rs", "")
+ });
+
+ let user2_repo = git2::Repository::open(&user2_git_project.root()).unwrap();
+ let url = "../dep2";
+ git::add_submodule(&user2_repo, url, Path::new("dep2"));
+ git::commit(&user2_repo);
+
+ let user1_repo = git2::Repository::open(&user1_git_project.root()).unwrap();
+ let url = user2_git_project.url();
+ git::add_submodule(&user1_repo, url.as_str(), Path::new("user2/dep1"));
+ git::commit(&user1_repo);
+
+ let project = project()
+ .file(
+ "Cargo.toml",
+ &format!(
+ r#"
+ [package]
+ name = "foo"
+ version = "0.5.0"
+
+ [dependencies.dep1]
+ git = '{}'
+ "#,
+ user1_git_project.url()
+ ),
+ )
+ .file("src/main.rs", &main_file(r#""hello""#, &[]))
+ .build();
+
+ project
+ .cargo("build")
+ .with_stderr(&format!(
+ "\
+[UPDATING] git repository `{}`
+[UPDATING] git submodule `{}`
+[UPDATING] git submodule `{}`
+[COMPILING] dep1 v0.5.0 ({}#[..])
+[COMPILING] foo v0.5.0 ([CWD])
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+",
+ path2url(&user1_git_project.root()),
+ path2url(&user2_git_project.root()),
+ path2url(&user2_git_project2.root()),
+ path2url(&user1_git_project.root()),
+ ))
+ .run();
+
+ assert!(project.bin("foo").is_file());
+}
diff --git a/src/tools/cargo/tests/testsuite/install.rs b/src/tools/cargo/tests/testsuite/install.rs
index 9b881dfdc..0c7fc5037 100644
--- a/src/tools/cargo/tests/testsuite/install.rs
+++ b/src/tools/cargo/tests/testsuite/install.rs
@@ -58,6 +58,20 @@ fn simple() {
}
#[cargo_test]
+fn toolchain() {
+ pkg("foo", "0.0.1");
+
+ cargo_process("install +nightly")
+ .with_status(101)
+ .with_stderr(
+ "\
+[ERROR] invalid character `+` in package name: `+nightly`
+ Use `cargo +nightly install` if you meant to use the `nightly` toolchain.",
+ )
+ .run();
+}
+
+#[cargo_test]
fn simple_with_message_format() {
pkg("foo", "0.0.1");
@@ -964,7 +978,8 @@ fn compile_failure() {
"\
[ERROR] could not compile `foo` (bin \"foo\") due to previous error
[ERROR] failed to compile `foo v0.0.1 ([..])`, intermediate artifacts can be \
- found at `[..]target`
+ found at `[..]target`.\nTo reuse those artifacts with a future compilation, \
+ set the environment variable `CARGO_TARGET_DIR` to that path.
",
)
.run();
@@ -1269,7 +1284,8 @@ fn reports_unsuccessful_subcommand_result() {
.run();
cargo_process("fail")
.with_status(101)
- .with_stderr_contains("thread '[..]' panicked at 'explicit panic', [..]")
+ .with_stderr_contains("thread '[..]' panicked at [..]src/main.rs:1:[..]")
+ .with_stderr_contains("[..]explicit panic[..]")
.run();
}
@@ -2250,7 +2266,9 @@ fn failed_install_retains_temp_directory() {
)
.unwrap();
compare::match_contains(
- "error: failed to compile `foo v0.0.1`, intermediate artifacts can be found at `[..]`",
+ "error: failed to compile `foo v0.0.1`, intermediate artifacts can be found at \
+ `[..]`.\nTo reuse those artifacts with a future compilation, set the environment \
+ variable `CARGO_TARGET_DIR` to that path.",
&stderr,
None,
)
@@ -2258,7 +2276,7 @@ fn failed_install_retains_temp_directory() {
// Find the path in the output.
let start = stderr.find("found at `").unwrap() + 10;
- let end = stderr[start..].find('\n').unwrap() - 1;
+ let end = stderr[start..].find('.').unwrap() - 1;
let path = Path::new(&stderr[start..(end + start)]);
assert!(path.exists());
assert!(path.join("release/deps").exists());
diff --git a/src/tools/cargo/tests/testsuite/lockfile_compat.rs b/src/tools/cargo/tests/testsuite/lockfile_compat.rs
index aad8723c3..63148cc07 100644
--- a/src/tools/cargo/tests/testsuite/lockfile_compat.rs
+++ b/src/tools/cargo/tests/testsuite/lockfile_compat.rs
@@ -888,3 +888,81 @@ perhaps a crate was updated and forgotten to be re-vendored?
)
.run();
}
+
+#[cargo_test]
+fn v4_is_unstable() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ &format!(
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ "#,
+ ),
+ )
+ .file("src/lib.rs", "")
+ .file("Cargo.lock", "version = 4")
+ .build();
+
+ p.cargo("fetch")
+ .with_status(101)
+ .with_stderr(
+ "\
+error: failed to parse lock file at: [CWD]/Cargo.lock
+
+Caused by:
+ lock file version `4` was found, but this version of Cargo does not \
+ understand this lock file, perhaps Cargo needs to be updated?
+",
+ )
+ .run();
+
+ // On nightly, let the user know about the `-Z` flag.
+ p.cargo("fetch")
+ .masquerade_as_nightly_cargo(&["-Znext-lockfile-bump"])
+ .with_status(101)
+ .with_stderr(
+ "\
+error: failed to parse lock file at: [CWD]/Cargo.lock
+
+Caused by:
+ lock file version 4 requires `-Znext-lockfile-bump`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn v4_cannot_be_created_from_scratch() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ &format!(
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ "#,
+ ),
+ )
+ .file("src/lib.rs", "")
+ .build();
+
+ p.cargo("fetch -Znext-lockfile-bump")
+ .masquerade_as_nightly_cargo(&["-Znext-lockfile-bump"])
+ .run();
+
+ let lockfile = r#"# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "foo"
+version = "0.0.1"
+"#;
+
+ let lock = p.read_lockfile();
+ assert_match_exact(lockfile, &lock);
+}
diff --git a/src/tools/cargo/tests/testsuite/main.rs b/src/tools/cargo/tests/testsuite/main.rs
index 170a22667..2c282c0a3 100644
--- a/src/tools/cargo/tests/testsuite/main.rs
+++ b/src/tools/cargo/tests/testsuite/main.rs
@@ -123,6 +123,7 @@ mod rustdoc_extern_html;
mod rustdocflags;
mod rustflags;
mod rustup;
+mod script;
mod search;
mod shell_quoting;
mod source_replacement;
diff --git a/src/tools/cargo/tests/testsuite/profile_config.rs b/src/tools/cargo/tests/testsuite/profile_config.rs
index cf9807964..26104e7e7 100644
--- a/src/tools/cargo/tests/testsuite/profile_config.rs
+++ b/src/tools/cargo/tests/testsuite/profile_config.rs
@@ -267,7 +267,7 @@ fn profile_config_all_options() {
-C panic=abort \
-C lto[..]\
-C codegen-units=2 \
- -C debuginfo=2 \
+ -C debuginfo=2 [..]\
-C debug-assertions=on \
-C overflow-checks=off [..]\
-C rpath [..]\
@@ -437,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(TomlDebugInfo::Limited)); // "bar" from config
+ assert_eq!(p.debuginfo.into_inner(), 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)
@@ -446,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(TomlDebugInfo::Limited)); // SAME as normal
+ assert_eq!(bo.debuginfo.into_inner(), 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
@@ -455,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(TomlDebugInfo::Limited)); // SAME as normal
+ assert_eq!(po.debuginfo.into_inner(), 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
}
@@ -509,12 +509,13 @@ fn test_with_dev_profile() {
[DOWNLOADING] [..]
[DOWNLOADED] [..]
[COMPILING] somedep v1.0.0
-[RUNNING] `rustc --crate-name somedep [..]-C debuginfo=0[..]
+[RUNNING] `rustc --crate-name somedep [..]
[COMPILING] foo v0.1.0 [..]
-[RUNNING] `rustc --crate-name foo [..]-C debuginfo=0[..]
+[RUNNING] `rustc --crate-name foo [..]
[FINISHED] [..]
[EXECUTABLE] `[..]/target/debug/deps/foo-[..][EXE]`
",
)
+ .with_stdout_does_not_contain("[..] -C debuginfo=0[..]")
.run();
}
diff --git a/src/tools/cargo/tests/testsuite/profile_targets.rs b/src/tools/cargo/tests/testsuite/profile_targets.rs
index 0449e8ab3..a88ca34fd 100644
--- a/src/tools/cargo/tests/testsuite/profile_targets.rs
+++ b/src/tools/cargo/tests/testsuite/profile_targets.rs
@@ -88,11 +88,11 @@ fn profile_selection_build() {
.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 -C debuginfo=0[..]
+[RUNNING] `[..] rustc --crate-name bar bar/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 [..]
[COMPILING] bdep [..]
-[RUNNING] `[..] rustc --crate-name bdep bdep/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 -C debuginfo=0[..]
+[RUNNING] `[..] rustc --crate-name bdep bdep/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 [..]
[COMPILING] foo [..]
-[RUNNING] `[..] rustc --crate-name build_script_build build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=5 -C debuginfo=0[..]
+[RUNNING] `[..] rustc --crate-name build_script_build build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=5 [..]
[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,6 +100,7 @@ fn profile_selection_build() {
[FINISHED] dev [unoptimized + debuginfo] [..]
"
)
+ .with_stderr_does_not_contain("[..] -C debuginfo=0[..]")
.run();
p.cargo("build -vv")
.with_stderr_unordered(
@@ -154,8 +155,9 @@ fn profile_selection_build_all_targets() {
// `build.rs` is a plugin.
// - 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 with debuginfo=0.
+ // - We make sure that the build dependencies bar, bdep, and build.rs are built with
+ // debuginfo=0; but since we don't pass `-C debuginfo` when it's set to 0, we have to test
+ // explicitly that there's no `-C debuginfo` flag.
//
// - Dependency profiles:
// Pkg Target Profile Reason
@@ -181,24 +183,25 @@ 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 -C debuginfo=0[..]
+[RUNNING] `[..] rustc --crate-name bar bar/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 [..]
[COMPILING] bdep [..]
-[RUNNING] `[..] rustc --crate-name bdep bdep/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 -C debuginfo=0[..]
+[RUNNING] `[..] rustc --crate-name bdep bdep/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 [..]
[COMPILING] foo [..]
-[RUNNING] `[..] rustc --crate-name build_script_build build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=5 -C debuginfo=0[..]
+[RUNNING] `[..] rustc --crate-name build_script_build build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=5 [..]
[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 [..]`
-[RUNNING] `[..] rustc --crate-name foo src/lib.rs [..]--emit=[..]link[..]-C codegen-units=1 -C debuginfo=2 --test [..]`
+[RUNNING] `[..] rustc --crate-name foo src/lib.rs [..]--emit=[..]link[..]-C codegen-units=1 -C debuginfo=2 [..]--test [..]`
[RUNNING] `[..] rustc --crate-name foo src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=1 -C debuginfo=2 [..]`
-[RUNNING] `[..] rustc --crate-name foo src/main.rs [..]--emit=[..]link[..]-C codegen-units=1 -C debuginfo=2 --test [..]`
-[RUNNING] `[..] rustc --crate-name test1 tests/test1.rs [..]--emit=[..]link[..]-C codegen-units=1 -C debuginfo=2 --test [..]`
-[RUNNING] `[..] rustc --crate-name bench1 benches/bench1.rs [..]--emit=[..]link[..]-C codegen-units=1 -C debuginfo=2 --test [..]`
+[RUNNING] `[..] rustc --crate-name foo src/main.rs [..]--emit=[..]link[..]-C codegen-units=1 -C debuginfo=2 [..]--test [..]`
+[RUNNING] `[..] rustc --crate-name test1 tests/test1.rs [..]--emit=[..]link[..]-C codegen-units=1 -C debuginfo=2 [..]--test [..]`
+[RUNNING] `[..] rustc --crate-name bench1 benches/bench1.rs [..]--emit=[..]link[..]-C codegen-units=1 -C debuginfo=2 [..]--test [..]`
[RUNNING] `[..] rustc --crate-name foo src/main.rs [..]--crate-type bin --emit=[..]link -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..]`
[RUNNING] `[..] rustc --crate-name ex1 examples/ex1.rs [..]--crate-type bin --emit=[..]link -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..]`
[FINISHED] dev [unoptimized + debuginfo] [..]
"
)
+ .with_stderr_does_not_contain("[..] -C debuginfo=0[..]")
.run();
p.cargo("build -vv")
.with_stderr_unordered(
@@ -315,10 +318,10 @@ fn profile_selection_test() {
[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=3 -C debuginfo=2 [..]
[RUNNING] `[..] rustc --crate-name foo src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=3 -C debuginfo=2 [..]
-[RUNNING] `[..] rustc --crate-name foo src/lib.rs [..]--emit=[..]link[..]-C codegen-units=3 -C debuginfo=2 --test [..]
-[RUNNING] `[..] rustc --crate-name test1 tests/test1.rs [..]--emit=[..]link[..]-C codegen-units=3 -C debuginfo=2 --test [..]
+[RUNNING] `[..] rustc --crate-name foo src/lib.rs [..]--emit=[..]link[..]-C codegen-units=3 -C debuginfo=2 [..]--test [..]
+[RUNNING] `[..] rustc --crate-name test1 tests/test1.rs [..]--emit=[..]link[..]-C codegen-units=3 -C debuginfo=2 [..]--test [..]
[RUNNING] `[..] rustc --crate-name ex1 examples/ex1.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=3 -C debuginfo=2 [..]
-[RUNNING] `[..] rustc --crate-name foo src/main.rs [..]--emit=[..]link[..]-C codegen-units=3 -C debuginfo=2 --test [..]
+[RUNNING] `[..] rustc --crate-name foo src/main.rs [..]--emit=[..]link[..]-C codegen-units=3 -C debuginfo=2 [..]--test [..]
[RUNNING] `[..] rustc --crate-name foo src/main.rs [..]--crate-type bin --emit=[..]link -C panic=abort[..]-C codegen-units=3 -C debuginfo=2 [..]
[FINISHED] test [unoptimized + debuginfo] [..]
[RUNNING] `[..]/deps/foo-[..]`
@@ -513,10 +516,10 @@ fn profile_selection_check_all_targets() {
[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=[..]metadata -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..]
[RUNNING] `[..] rustc --crate-name foo src/lib.rs [..]--crate-type lib --emit=[..]metadata[..]-C codegen-units=1 -C debuginfo=2 [..]
-[RUNNING] `[..] rustc --crate-name foo src/lib.rs [..]--emit=[..]metadata[..]-C codegen-units=1 -C debuginfo=2 --test [..]
-[RUNNING] `[..] rustc --crate-name test1 tests/test1.rs [..]--emit=[..]metadata[..]-C codegen-units=1 -C debuginfo=2 --test [..]
-[RUNNING] `[..] rustc --crate-name foo src/main.rs [..]--emit=[..]metadata[..]-C codegen-units=1 -C debuginfo=2 --test [..]
-[RUNNING] `[..] rustc --crate-name bench1 benches/bench1.rs [..]--emit=[..]metadata[..]-C codegen-units=1 -C debuginfo=2 --test [..]
+[RUNNING] `[..] rustc --crate-name foo src/lib.rs [..]--emit=[..]metadata[..]-C codegen-units=1 -C debuginfo=2 [..]--test [..]
+[RUNNING] `[..] rustc --crate-name test1 tests/test1.rs [..]--emit=[..]metadata[..]-C codegen-units=1 -C debuginfo=2 [..]--test [..]
+[RUNNING] `[..] rustc --crate-name foo src/main.rs [..]--emit=[..]metadata[..]-C codegen-units=1 -C debuginfo=2 [..]--test [..]
+[RUNNING] `[..] rustc --crate-name bench1 benches/bench1.rs [..]--emit=[..]metadata[..]-C codegen-units=1 -C debuginfo=2 [..]--test [..]
[RUNNING] `[..] rustc --crate-name ex1 examples/ex1.rs [..]--crate-type bin --emit=[..]metadata -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..]
[RUNNING] `[..] rustc --crate-name foo src/main.rs [..]--crate-type bin --emit=[..]metadata -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..]
[FINISHED] dev [unoptimized + debuginfo] [..]
@@ -615,11 +618,11 @@ fn profile_selection_check_all_targets_test() {
[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=[..]metadata[..]-C codegen-units=3 -C debuginfo=2 [..]
-[RUNNING] `[..] rustc --crate-name foo src/lib.rs [..]--emit=[..]metadata[..]-C codegen-units=3 -C debuginfo=2 --test [..]
-[RUNNING] `[..] rustc --crate-name test1 tests/test1.rs [..]--emit=[..]metadata[..]-C codegen-units=3 -C debuginfo=2 --test [..]
-[RUNNING] `[..] rustc --crate-name foo src/main.rs [..]--emit=[..]metadata[..]-C codegen-units=3 -C debuginfo=2 --test [..]
-[RUNNING] `[..] rustc --crate-name bench1 benches/bench1.rs [..]--emit=[..]metadata[..]-C codegen-units=3 -C debuginfo=2 --test [..]
-[RUNNING] `[..] rustc --crate-name ex1 examples/ex1.rs [..]--emit=[..]metadata[..]-C codegen-units=3 -C debuginfo=2 --test [..]
+[RUNNING] `[..] rustc --crate-name foo src/lib.rs [..]--emit=[..]metadata[..]-C codegen-units=3 -C debuginfo=2 [..]--test [..]
+[RUNNING] `[..] rustc --crate-name test1 tests/test1.rs [..]--emit=[..]metadata[..]-C codegen-units=3 -C debuginfo=2 [..]--test [..]
+[RUNNING] `[..] rustc --crate-name foo src/main.rs [..]--emit=[..]metadata[..]-C codegen-units=3 -C debuginfo=2 [..]--test [..]
+[RUNNING] `[..] rustc --crate-name bench1 benches/bench1.rs [..]--emit=[..]metadata[..]-C codegen-units=3 -C debuginfo=2 [..]--test [..]
+[RUNNING] `[..] rustc --crate-name ex1 examples/ex1.rs [..]--emit=[..]metadata[..]-C codegen-units=3 -C debuginfo=2 [..]--test [..]
[FINISHED] test [unoptimized + debuginfo] [..]
").run();
diff --git a/src/tools/cargo/tests/testsuite/profiles.rs b/src/tools/cargo/tests/testsuite/profiles.rs
index 2d2646fe3..465ab3b99 100644
--- a/src/tools/cargo/tests/testsuite/profiles.rs
+++ b/src/tools/cargo/tests/testsuite/profiles.rs
@@ -66,7 +66,7 @@ fn opt_level_override_0() {
[COMPILING] test v0.0.0 ([CWD])
[RUNNING] `rustc --crate-name test src/lib.rs [..]--crate-type lib \
--emit=[..]link[..]\
- -C debuginfo=2 \
+ -C debuginfo=2 [..]\
-C metadata=[..] \
--out-dir [..] \
-L dependency=[CWD]/target/debug/deps`
@@ -99,7 +99,7 @@ fn debug_override_1() {
[COMPILING] test v0.0.0 ([CWD])
[RUNNING] `rustc --crate-name test src/lib.rs [..]--crate-type lib \
--emit=[..]link[..]\
- -C debuginfo=1 \
+ -C debuginfo=1 [..]\
-C metadata=[..] \
--out-dir [..] \
-L dependency=[CWD]/target/debug/deps`
@@ -136,7 +136,7 @@ fn check_opt_level_override(profile_level: &str, rustc_level: &str) {
[RUNNING] `rustc --crate-name test src/lib.rs [..]--crate-type lib \
--emit=[..]link \
-C opt-level={level}[..]\
- -C debuginfo=2 \
+ -C debuginfo=2 [..]\
-C debug-assertions=on \
-C metadata=[..] \
--out-dir [..] \
@@ -211,7 +211,7 @@ fn top_level_overrides_deps() {
--emit=[..]link \
-C prefer-dynamic \
-C opt-level=1[..]\
- -C debuginfo=2 \
+ -C debuginfo=2 [..]\
-C metadata=[..] \
--out-dir [CWD]/target/release/deps \
-L dependency=[CWD]/target/release/deps`
@@ -219,7 +219,7 @@ fn top_level_overrides_deps() {
[RUNNING] `rustc --crate-name test src/lib.rs [..]--crate-type lib \
--emit=[..]link \
-C opt-level=1[..]\
- -C debuginfo=2 \
+ -C debuginfo=2 [..]\
-C metadata=[..] \
--out-dir [..] \
-L dependency=[CWD]/target/release/deps \
@@ -467,10 +467,11 @@ fn debug_0_report() {
.with_stderr(
"\
[COMPILING] foo v0.1.0 [..]
-[RUNNING] `rustc --crate-name foo src/lib.rs [..]-C debuginfo=0 [..]
+[RUNNING] `rustc --crate-name foo src/lib.rs [..]
[FINISHED] dev [unoptimized] target(s) in [..]
",
)
+ .with_stderr_does_not_contain("-C debuginfo")
.run();
}
@@ -742,3 +743,42 @@ Caused by:
)
.run();
}
+
+#[cargo_test(nightly, reason = "debug options stabilized in 1.70")]
+fn debug_options_valid() {
+ let build = |option| {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ &format!(
+ r#"
+ [package]
+ name = "foo"
+ authors = []
+ version = "0.0.0"
+
+ [profile.dev]
+ debug = "{option}"
+ "#
+ ),
+ )
+ .file("src/main.rs", "fn main() {}")
+ .build();
+
+ p.cargo("build -v")
+ };
+
+ for (option, cli) in [
+ ("line-directives-only", "line-directives-only"),
+ ("line-tables-only", "line-tables-only"),
+ ("limited", "1"),
+ ("full", "2"),
+ ] {
+ build(option)
+ .with_stderr_contains(&format!("[RUNNING] `rustc [..]-C debuginfo={cli} [..]"))
+ .run();
+ }
+ build("none")
+ .with_stderr_does_not_contain("[..]-C debuginfo[..]")
+ .run();
+}
diff --git a/src/tools/cargo/tests/testsuite/required_features.rs b/src/tools/cargo/tests/testsuite/required_features.rs
index ac6c9d233..88be89fd4 100644
--- a/src/tools/cargo/tests/testsuite/required_features.rs
+++ b/src/tools/cargo/tests/testsuite/required_features.rs
@@ -658,7 +658,9 @@ Consider enabling some of the needed features by passing, e.g., `--features=\"a\
"\
[INSTALLING] foo v0.0.1 ([..])
[ERROR] failed to compile `foo v0.0.1 ([..])`, intermediate artifacts can be found at \
- `[..]target`
+ `[..]target`.
+To reuse those artifacts with a future compilation, set the environment \
+variable `CARGO_TARGET_DIR` to that path.
Caused by:
target `foo` in package `foo` requires the features: `a`
@@ -678,7 +680,8 @@ Caused by:
"\
[INSTALLING] foo v0.0.1 ([..])
[ERROR] failed to compile `foo v0.0.1 ([..])`, intermediate artifacts can be found at \
- `[..]target`
+ `[..]target`.\nTo reuse those artifacts with a future compilation, set the environment \
+ variable `CARGO_TARGET_DIR` to that path.
Caused by:
target `foo` in package `foo` requires the features: `a`
diff --git a/src/tools/cargo/tests/testsuite/run.rs b/src/tools/cargo/tests/testsuite/run.rs
index aa210d6ae..586502288 100644
--- a/src/tools/cargo/tests/testsuite/run.rs
+++ b/src/tools/cargo/tests/testsuite/run.rs
@@ -777,14 +777,14 @@ fast2",
[COMPILING] bar v0.5.0 ([CWD]/bar)
[RUNNING] `rustc --crate-name bar bar/src/bar.rs [..]--crate-type lib \
--emit=[..]link[..]\
- -C debuginfo=2 \
+ -C debuginfo=2 [..]\
-C metadata=[..] \
--out-dir [CWD]/target/debug/deps \
-L dependency=[CWD]/target/debug/deps`
[COMPILING] foo v0.0.1 ([CWD])
[RUNNING] `rustc --crate-name a examples/a.rs [..]--crate-type bin \
--emit=[..]link[..]\
- -C debuginfo=2 \
+ -C debuginfo=2 [..]\
-C metadata=[..] \
--out-dir [CWD]/target/debug/examples \
-L dependency=[CWD]/target/debug/deps \
diff --git a/src/tools/cargo/tests/testsuite/rustc.rs b/src/tools/cargo/tests/testsuite/rustc.rs
index 65e0740f8..6e3d69cf7 100644
--- a/src/tools/cargo/tests/testsuite/rustc.rs
+++ b/src/tools/cargo/tests/testsuite/rustc.rs
@@ -18,7 +18,7 @@ fn build_lib_for_foo() {
"\
[COMPILING] foo v0.0.1 ([CWD])
[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib \
- --emit=[..]link[..]-C debuginfo=2 \
+ --emit=[..]link[..]-C debuginfo=2 [..]\
-C metadata=[..] \
--out-dir [..] \
-L dependency=[CWD]/target/debug/deps`
@@ -40,7 +40,7 @@ fn lib() {
"\
[COMPILING] foo v0.0.1 ([CWD])
[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib \
- --emit=[..]link[..]-C debuginfo=2 \
+ --emit=[..]link[..]-C debuginfo=2 [..]\
-C debug-assertions=off \
-C metadata=[..] \
--out-dir [..] \
@@ -63,12 +63,12 @@ fn build_main_and_allow_unstable_options() {
"\
[COMPILING] {name} v{version} ([CWD])
[RUNNING] `rustc --crate-name {name} src/lib.rs [..]--crate-type lib \
- --emit=[..]link[..]-C debuginfo=2 \
+ --emit=[..]link[..]-C debuginfo=2 [..]\
-C metadata=[..] \
--out-dir [..] \
-L dependency=[CWD]/target/debug/deps`
[RUNNING] `rustc --crate-name {name} src/main.rs [..]--crate-type bin \
- --emit=[..]link[..]-C debuginfo=2 \
+ --emit=[..]link[..]-C debuginfo=2 [..]\
-C debug-assertions \
-C metadata=[..] \
--out-dir [..] \
@@ -109,10 +109,10 @@ fn build_with_args_to_one_of_multiple_binaries() {
"\
[COMPILING] foo v0.0.1 ([CWD])
[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib --emit=[..]link[..]\
- -C debuginfo=2 -C metadata=[..] \
+ -C debuginfo=2 [..]-C metadata=[..] \
--out-dir [..]`
[RUNNING] `rustc --crate-name bar src/bin/bar.rs [..]--crate-type bin --emit=[..]link[..]\
- -C debuginfo=2 -C debug-assertions [..]`
+ -C debuginfo=2 [..]-C debug-assertions [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
)
@@ -381,9 +381,9 @@ fn build_with_args_to_one_of_multiple_tests() {
"\
[COMPILING] foo v0.0.1 ([CWD])
[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib --emit=[..]link[..]\
- -C debuginfo=2 -C metadata=[..] \
+ -C debuginfo=2 [..]-C metadata=[..] \
--out-dir [..]`
-[RUNNING] `rustc --crate-name bar tests/bar.rs [..]--emit=[..]link[..]-C debuginfo=2 \
+[RUNNING] `rustc --crate-name bar tests/bar.rs [..]--emit=[..]link[..]-C debuginfo=2 [..]\
-C debug-assertions [..]--test[..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
@@ -420,7 +420,7 @@ fn build_foo_with_bar_dependency() {
[COMPILING] bar v0.1.0 ([..])
[RUNNING] `[..] -C debuginfo=2 [..]`
[COMPILING] foo v0.0.1 ([CWD])
-[RUNNING] `[..] -C debuginfo=2 -C debug-assertions [..]`
+[RUNNING] `[..] -C debuginfo=2 [..]-C debug-assertions [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
)
@@ -478,7 +478,7 @@ fn targets_selected_default() {
// unit test
.with_stderr_does_not_contain(
"[RUNNING] `rustc --crate-name foo src/main.rs [..]--emit=[..]link \
- -C debuginfo=2 --test [..]",
+ -C debuginfo=2 [..]--test [..]",
)
.run();
}
@@ -495,7 +495,7 @@ fn targets_selected_all() {
// unit test
.with_stderr_contains(
"[RUNNING] `rustc --crate-name foo src/main.rs [..]--emit=[..]link[..]\
- -C debuginfo=2 --test [..]",
+ -C debuginfo=2 [..]--test [..]",
)
.run();
}
diff --git a/src/tools/cargo/tests/testsuite/script.rs b/src/tools/cargo/tests/testsuite/script.rs
new file mode 100644
index 000000000..fcf58de69
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/script.rs
@@ -0,0 +1,1184 @@
+use cargo_test_support::basic_manifest;
+use cargo_test_support::registry::Package;
+
+const ECHO_SCRIPT: &str = r#"#!/usr/bin/env cargo
+
+fn main() {
+ let mut args = std::env::args_os();
+ let bin = args.next().unwrap().to_str().unwrap().to_owned();
+ let args = args.collect::<Vec<_>>();
+ println!("bin: {bin}");
+ println!("args: {args:?}");
+}
+
+#[test]
+fn test () {}
+"#;
+
+#[cfg(unix)]
+fn path() -> Vec<std::path::PathBuf> {
+ std::env::split_paths(&std::env::var_os("PATH").unwrap_or_default()).collect()
+}
+
+#[cargo_test]
+fn basic_rs() {
+ let p = cargo_test_support::project()
+ .file("echo.rs", ECHO_SCRIPT)
+ .build();
+
+ p.cargo("-Zscript -v echo.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"bin: [..]/debug/echo[EXE]
+args: []
+"#,
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+[COMPILING] echo v0.0.0 ([ROOT]/foo)
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+[RUNNING] `[..]/debug/echo[EXE]`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn basic_path() {
+ let p = cargo_test_support::project()
+ .file("echo", ECHO_SCRIPT)
+ .build();
+
+ p.cargo("-Zscript -v ./echo")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"bin: [..]/debug/echo[EXE]
+args: []
+"#,
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+[COMPILING] echo v0.0.0 ([ROOT]/foo)
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+[RUNNING] `[..]/debug/echo[EXE]`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn basic_cargo_toml() {
+ let p = cargo_test_support::project()
+ .file("src/main.rs", ECHO_SCRIPT)
+ .build();
+
+ p.cargo("-Zscript -v Cargo.toml")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"bin: target/debug/foo[EXE]
+args: []
+"#,
+ )
+ .with_stderr(
+ "\
+[COMPILING] foo v0.0.1 ([ROOT]/foo)
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+[RUNNING] `target/debug/foo[EXE]`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn path_required() {
+ let p = cargo_test_support::project()
+ .file("echo", ECHO_SCRIPT)
+ .build();
+
+ p.cargo("-Zscript -v echo")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_status(101)
+ .with_stdout("")
+ .with_stderr(
+ "\
+error: no such command: `echo`
+
+<tab>Did you mean `bench`?
+
+<tab>View all installed commands with `cargo --list`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+#[cfg(unix)]
+fn manifest_precedence_over_plugins() {
+ let p = cargo_test_support::project()
+ .file("echo.rs", ECHO_SCRIPT)
+ .executable(std::path::Path::new("path-test").join("cargo-echo.rs"), "")
+ .build();
+
+ // With path - fmt is there with known description
+ let mut path = path();
+ path.push(p.root().join("path-test"));
+ let path = std::env::join_paths(path.iter()).unwrap();
+
+ p.cargo("-Zscript -v echo.rs")
+ .env("PATH", &path)
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"bin: [..]/debug/echo[EXE]
+args: []
+"#,
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+[COMPILING] echo v0.0.0 ([ROOT]/foo)
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+[RUNNING] `[..]/debug/echo[EXE]`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+#[cfg(unix)]
+fn warn_when_plugin_masks_manifest_on_stable() {
+ let p = cargo_test_support::project()
+ .file("echo.rs", ECHO_SCRIPT)
+ .executable(std::path::Path::new("path-test").join("cargo-echo.rs"), "")
+ .build();
+
+ let mut path = path();
+ path.push(p.root().join("path-test"));
+ let path = std::env::join_paths(path.iter()).unwrap();
+
+ p.cargo("-v echo.rs")
+ .env("PATH", &path)
+ .with_stdout("")
+ .with_stderr(
+ "\
+warning: external subcommand `echo.rs` has the appearance of a manfiest-command
+This was previously accepted but will be phased out when `-Zscript` is stabilized.
+For more information, see issue #12207 <https://github.com/rust-lang/cargo/issues/12207>.
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn requires_nightly() {
+ let p = cargo_test_support::project()
+ .file("echo.rs", ECHO_SCRIPT)
+ .build();
+
+ p.cargo("-v echo.rs")
+ .with_status(101)
+ .with_stdout("")
+ .with_stderr(
+ "\
+error: running `echo.rs` requires `-Zscript`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn requires_z_flag() {
+ let p = cargo_test_support::project()
+ .file("echo.rs", ECHO_SCRIPT)
+ .build();
+
+ p.cargo("-v echo.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_status(101)
+ .with_stdout("")
+ .with_stderr(
+ "\
+error: running `echo.rs` requires `-Zscript`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn clean_output_with_edition() {
+ let script = r#"#!/usr/bin/env cargo
+
+//! ```cargo
+//! [package]
+//! edition = "2018"
+//! ```
+
+fn main() {
+ println!("Hello world!");
+}"#;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .build();
+
+ p.cargo("-Zscript -v script.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"Hello world!
+"#,
+ )
+ .with_stderr(
+ "\
+[COMPILING] script v0.0.0 ([ROOT]/foo)
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+[RUNNING] `[..]/debug/script[EXE]`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn warning_without_edition() {
+ let script = r#"#!/usr/bin/env cargo
+
+//! ```cargo
+//! [package]
+//! ```
+
+fn main() {
+ println!("Hello world!");
+}"#;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .build();
+
+ p.cargo("-Zscript -v script.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"Hello world!
+"#,
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+[COMPILING] script v0.0.0 ([ROOT]/foo)
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+[RUNNING] `[..]/debug/script[EXE]`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn rebuild() {
+ let script = r#"#!/usr/bin/env cargo-eval
+
+fn main() {
+ let msg = option_env!("_MESSAGE").unwrap_or("undefined");
+ println!("msg = {}", msg);
+}"#;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .build();
+
+ p.cargo("-Zscript -v script.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"msg = undefined
+"#,
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+[COMPILING] script v0.0.0 ([ROOT]/foo)
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+[RUNNING] `[..]/debug/script[EXE]`
+",
+ )
+ .run();
+
+ // Verify we don't rebuild
+ p.cargo("-Zscript -v script.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"msg = undefined
+"#,
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+[RUNNING] `[..]/debug/script[EXE]`
+",
+ )
+ .run();
+
+ // Verify we do rebuild
+ p.cargo("-Zscript -v script.rs")
+ .env("_MESSAGE", "hello")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"msg = hello
+"#,
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+[COMPILING] script v0.0.0 ([ROOT]/foo)
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+[RUNNING] `[..]/debug/script[EXE]`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn use_script_config() {
+ let script = ECHO_SCRIPT;
+ let _ = cargo_test_support::project()
+ .at("script")
+ .file("script.rs", script)
+ .build();
+
+ let p = cargo_test_support::project()
+ .file(
+ ".cargo/config",
+ r#"
+[build]
+rustc = "non-existent-rustc"
+"#,
+ )
+ .file("script.rs", script)
+ .build();
+
+ // Verify the config is bad
+ p.cargo("-Zscript script.rs -NotAnArg")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_status(101)
+ .with_stderr_contains(
+ "\
+[ERROR] could not execute process `non-existent-rustc -vV` (never executed)
+",
+ )
+ .run();
+
+ // Verify that the config isn't used
+ p.cargo("-Zscript ../script/script.rs -NotAnArg")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"bin: [..]/debug/script[EXE]
+args: ["-NotAnArg"]
+"#,
+ )
+ .run();
+}
+
+#[cargo_test]
+fn default_programmatic_verbosity() {
+ let script = ECHO_SCRIPT;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .build();
+
+ p.cargo("-Zscript script.rs -NotAnArg")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"bin: [..]/debug/script[EXE]
+args: ["-NotAnArg"]
+"#,
+ )
+ .with_stderr(
+ "\
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn quiet() {
+ let script = ECHO_SCRIPT;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .build();
+
+ p.cargo("-Zscript -q script.rs -NotAnArg")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"bin: [..]/debug/script[EXE]
+args: ["-NotAnArg"]
+"#,
+ )
+ .with_stderr(
+ "\
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn test_line_numbering_preserved() {
+ let script = r#"#!/usr/bin/env cargo
+
+fn main() {
+ println!("line: {}", line!());
+}
+"#;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .build();
+
+ p.cargo("-Zscript -v script.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"line: 4
+"#,
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+[COMPILING] script v0.0.0 ([ROOT]/foo)
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+[RUNNING] `[..]/debug/script[EXE]`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn test_escaped_hyphen_arg() {
+ let script = ECHO_SCRIPT;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .build();
+
+ p.cargo("-Zscript -v -- script.rs -NotAnArg")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"bin: [..]/debug/script[EXE]
+args: ["-NotAnArg"]
+"#,
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+[COMPILING] script v0.0.0 ([ROOT]/foo)
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+[RUNNING] `[..]/debug/script[EXE] -NotAnArg`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn test_unescaped_hyphen_arg() {
+ let script = ECHO_SCRIPT;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .build();
+
+ p.cargo("-Zscript -v script.rs -NotAnArg")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"bin: [..]/debug/script[EXE]
+args: ["-NotAnArg"]
+"#,
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+[COMPILING] script v0.0.0 ([ROOT]/foo)
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+[RUNNING] `[..]/debug/script[EXE] -NotAnArg`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn test_same_flags() {
+ let script = ECHO_SCRIPT;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .build();
+
+ p.cargo("-Zscript -v script.rs --help")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"bin: [..]/debug/script[EXE]
+args: ["--help"]
+"#,
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+[COMPILING] script v0.0.0 ([ROOT]/foo)
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+[RUNNING] `[..]/debug/script[EXE] --help`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn test_name_has_weird_chars() {
+ let script = ECHO_SCRIPT;
+ let p = cargo_test_support::project()
+ .file("s-h.w§c!.rs", script)
+ .build();
+
+ p.cargo("-Zscript -v s-h.w§c!.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"bin: [..]/debug/s-h-w-c-[EXE]
+args: []
+"#,
+ )
+ .with_stderr(
+ r#"[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+[COMPILING] s-h-w-c- v0.0.0 ([ROOT]/foo)
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+[RUNNING] `[..]/debug/s-h-w-c-[EXE]`
+"#,
+ )
+ .run();
+}
+
+#[cargo_test]
+fn script_like_dir() {
+ let p = cargo_test_support::project()
+ .file("script.rs/foo", "something")
+ .build();
+
+ p.cargo("-Zscript -v script.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_status(101)
+ .with_stderr(
+ "\
+error: manifest path `script.rs` is a directory but expected a file
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn missing_script_rs() {
+ let p = cargo_test_support::project().build();
+
+ p.cargo("-Zscript -v script.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_status(101)
+ .with_stderr(
+ "\
+[ERROR] manifest path `script.rs` does not exist
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn test_name_same_as_dependency() {
+ Package::new("script", "1.0.0").publish();
+ let script = r#"#!/usr/bin/env cargo
+
+//! ```cargo
+//! [dependencies]
+//! script = "1.0.0"
+//! ```
+
+fn main() {
+ println!("Hello world!");
+}"#;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .build();
+
+ p.cargo("-Zscript -v script.rs --help")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"Hello world!
+"#,
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+[UPDATING] `dummy-registry` index
+[DOWNLOADING] crates ...
+[DOWNLOADED] script v1.0.0 (registry `dummy-registry`)
+[COMPILING] script v1.0.0
+[COMPILING] script v0.0.0 ([ROOT]/foo)
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+[RUNNING] `[..]/debug/script[EXE] --help`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn test_path_dep() {
+ let script = r#"#!/usr/bin/env cargo
+
+//! ```cargo
+//! [dependencies]
+//! bar.path = "./bar"
+//! ```
+
+fn main() {
+ println!("Hello world!");
+}"#;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .file("src/lib.rs", "pub fn foo() {}")
+ .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
+ .file("bar/src/lib.rs", "pub fn bar() {}")
+ .build();
+
+ p.cargo("-Zscript -v script.rs --help")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"Hello world!
+"#,
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+[COMPILING] bar v0.0.1 ([ROOT]/foo/bar)
+[COMPILING] script v0.0.0 ([ROOT]/foo)
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+[RUNNING] `[..]/debug/script[EXE] --help`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn test_no_build_rs() {
+ let script = r#"#!/usr/bin/env cargo
+
+fn main() {
+ println!("Hello world!");
+}"#;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .file("build.rs", "broken")
+ .build();
+
+ p.cargo("-Zscript -v script.rs --help")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"Hello world!
+"#,
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+[COMPILING] script v0.0.0 ([ROOT]/foo)
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+[RUNNING] `[..]/debug/script[EXE] --help`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn test_no_autobins() {
+ let script = r#"#!/usr/bin/env cargo
+
+fn main() {
+ println!("Hello world!");
+}"#;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .file("src/bin/not-script/main.rs", "fn main() {}")
+ .build();
+
+ p.cargo("-Zscript -v script.rs --help")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"Hello world!
+"#,
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+[COMPILING] script v0.0.0 ([ROOT]/foo)
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+[RUNNING] `[..]/debug/script[EXE] --help`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn implicit_target_dir() {
+ let script = ECHO_SCRIPT;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .build();
+
+ p.cargo("-Zscript -v script.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"bin: [ROOT]/home/.cargo/target/[..]/debug/script[EXE]
+args: []
+"#,
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+[COMPILING] script v0.0.0 ([ROOT]/foo)
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+[RUNNING] `[ROOT]/home/.cargo/target/[..]/debug/script[EXE]`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn no_local_lockfile() {
+ let script = ECHO_SCRIPT;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .build();
+ let local_lockfile_path = p.root().join("Cargo.lock");
+
+ assert!(!local_lockfile_path.exists());
+
+ p.cargo("-Zscript -v script.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"bin: [ROOT]/home/.cargo/target/[..]/debug/script[EXE]
+args: []
+"#,
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+[COMPILING] script v0.0.0 ([ROOT]/foo)
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+[RUNNING] `[ROOT]/home/.cargo/target/[..]/debug/script[EXE]`
+",
+ )
+ .run();
+
+ assert!(!local_lockfile_path.exists());
+}
+
+#[cargo_test]
+fn cmd_check_requires_nightly() {
+ let script = ECHO_SCRIPT;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .build();
+
+ p.cargo("check --manifest-path script.rs")
+ .with_status(101)
+ .with_stdout("")
+ .with_stderr(
+ "\
+error: embedded manifest `[ROOT]/foo/script.rs` requires `-Zscript`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn cmd_check_requires_z_flag() {
+ let script = ECHO_SCRIPT;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .build();
+
+ p.cargo("check --manifest-path script.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_status(101)
+ .with_stdout("")
+ .with_stderr(
+ "\
+error: embedded manifest `[ROOT]/foo/script.rs` requires `-Zscript`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn cmd_check_with_embedded() {
+ let script = ECHO_SCRIPT;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .build();
+
+ p.cargo("-Zscript check --manifest-path script.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ "\
+",
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+[CHECKING] script v0.0.0 ([ROOT]/foo)
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn cmd_check_with_missing_script_rs() {
+ let p = cargo_test_support::project().build();
+
+ p.cargo("-Zscript check --manifest-path script.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_status(101)
+ .with_stdout(
+ "\
+",
+ )
+ .with_stderr(
+ "\
+[ERROR] manifest path `script.rs` does not exist
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn cmd_check_with_missing_script() {
+ let p = cargo_test_support::project().build();
+
+ p.cargo("-Zscript check --manifest-path script")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_status(101)
+ .with_stdout(
+ "\
+",
+ )
+ .with_stderr(
+ "\
+[ERROR] the manifest-path must be a path to a Cargo.toml file
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn cmd_build_with_embedded() {
+ let script = ECHO_SCRIPT;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .build();
+
+ p.cargo("-Zscript build --manifest-path script.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ "\
+",
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+[COMPILING] script v0.0.0 ([ROOT]/foo)
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn cmd_test_with_embedded() {
+ let script = ECHO_SCRIPT;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .build();
+
+ p.cargo("-Zscript test --manifest-path script.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ "
+running 1 test
+test test ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [..]s
+
+",
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+[COMPILING] script v0.0.0 ([ROOT]/foo)
+[FINISHED] test [unoptimized + debuginfo] target(s) in [..]s
+[RUNNING] unittests script.rs ([..])
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn cmd_clean_with_embedded() {
+ let script = ECHO_SCRIPT;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .build();
+
+ // Ensure there is something to clean
+ p.cargo("-Zscript script.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .run();
+
+ p.cargo("-Zscript clean --manifest-path script.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ "\
+",
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn cmd_generate_lockfile_with_embedded() {
+ let script = ECHO_SCRIPT;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .build();
+
+ p.cargo("-Zscript generate-lockfile --manifest-path script.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ "\
+",
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn cmd_metadata_with_embedded() {
+ let script = ECHO_SCRIPT;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .build();
+
+ p.cargo("-Zscript metadata --manifest-path script.rs --format-version=1")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_json(
+ r#"
+ {
+ "packages": [
+ {
+ "authors": [
+ ],
+ "categories": [],
+ "default_run": null,
+ "name": "script",
+ "version": "0.0.0",
+ "id": "script[..]",
+ "keywords": [],
+ "source": null,
+ "dependencies": [],
+ "edition": "[..]",
+ "license": null,
+ "license_file": null,
+ "links": null,
+ "description": null,
+ "readme": null,
+ "repository": null,
+ "rust_version": null,
+ "homepage": null,
+ "documentation": null,
+ "homepage": null,
+ "documentation": null,
+ "targets": [
+ {
+ "kind": [
+ "bin"
+ ],
+ "crate_types": [
+ "bin"
+ ],
+ "doc": true,
+ "doctest": false,
+ "test": true,
+ "edition": "[..]",
+ "name": "script",
+ "src_path": "[..]/script.rs"
+ }
+ ],
+ "features": {},
+ "manifest_path": "[..]script.rs",
+ "metadata": null,
+ "publish": []
+ }
+ ],
+ "workspace_members": ["script 0.0.0 (path+file:[..]foo)"],
+ "workspace_default_members": ["script 0.0.0 (path+file:[..]foo)"],
+ "resolve": {
+ "nodes": [
+ {
+ "dependencies": [],
+ "deps": [],
+ "features": [],
+ "id": "script 0.0.0 (path+file:[..]foo)"
+ }
+ ],
+ "root": "script 0.0.0 (path+file:[..]foo)"
+ },
+ "target_directory": "[ROOT]/home/.cargo/target/[..]",
+ "version": 1,
+ "workspace_root": "[..]/foo",
+ "metadata": null
+ }"#,
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn cmd_read_manifest_with_embedded() {
+ let script = ECHO_SCRIPT;
+ let p = cargo_test_support::project()
+ .file("script.rs", script)
+ .build();
+
+ p.cargo("-Zscript read-manifest --manifest-path script.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_json(
+ r#"
+{
+ "authors": [
+ ],
+ "categories": [],
+ "default_run": null,
+ "name":"script",
+ "readme": null,
+ "homepage": null,
+ "documentation": null,
+ "repository": null,
+ "rust_version": null,
+ "version":"0.0.0",
+ "id":"script[..]0.0.0[..](path+file://[..]/foo)",
+ "keywords": [],
+ "license": null,
+ "license_file": null,
+ "links": null,
+ "description": null,
+ "edition": "[..]",
+ "source":null,
+ "dependencies":[],
+ "targets":[{
+ "kind":["bin"],
+ "crate_types":["bin"],
+ "doc": true,
+ "doctest": false,
+ "test": true,
+ "edition": "[..]",
+ "name":"script",
+ "src_path":"[..]/script.rs"
+ }],
+ "features":{},
+ "manifest_path":"[..]script.rs",
+ "metadata": null,
+ "publish": []
+}"#,
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn cmd_run_with_embedded() {
+ let p = cargo_test_support::project()
+ .file("script.rs", ECHO_SCRIPT)
+ .build();
+
+ p.cargo("-Zscript run --manifest-path script.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ r#"bin: [..]/debug/script[EXE]
+args: []
+"#,
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+[COMPILING] script v0.0.0 ([ROOT]/foo)
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+[RUNNING] `[..]/debug/script[EXE]`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn cmd_tree_with_embedded() {
+ let p = cargo_test_support::project()
+ .file("script.rs", ECHO_SCRIPT)
+ .build();
+
+ p.cargo("-Zscript tree --manifest-path script.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ "\
+script v0.0.0 ([ROOT]/foo)
+",
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn cmd_update_with_embedded() {
+ let p = cargo_test_support::project()
+ .file("script.rs", ECHO_SCRIPT)
+ .build();
+
+ p.cargo("-Zscript update --manifest-path script.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_stdout(
+ "\
+",
+ )
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn cmd_verify_project_with_embedded() {
+ let p = cargo_test_support::project()
+ .file("script.rs", ECHO_SCRIPT)
+ .build();
+
+ p.cargo("-Zscript verify-project --manifest-path script.rs")
+ .masquerade_as_nightly_cargo(&["script"])
+ .with_json(r#"{"success":"true"}"#)
+ .with_stderr(
+ "\
+[WARNING] `package.edition` is unspecifiead, defaulting to `2021`
+",
+ )
+ .run();
+}
diff --git a/src/tools/cargo/tests/testsuite/test.rs b/src/tools/cargo/tests/testsuite/test.rs
index add0a991f..6a062cfb6 100644
--- a/src/tools/cargo/tests/testsuite/test.rs
+++ b/src/tools/cargo/tests/testsuite/test.rs
@@ -387,8 +387,9 @@ test test_hello ... FAILED
failures:
---- test_hello stdout ----
-[..]thread '[..]' panicked at 'assertion failed:[..]",
+[..]thread '[..]' panicked at [..]",
)
+ .with_stdout_contains("[..]assertion failed[..]")
.with_stdout_contains("[..]`(left == right)`[..]")
.with_stdout_contains("[..]left: `\"hello\"`,[..]")
.with_stdout_contains("[..]right: `\"nope\"`[..]")
@@ -437,10 +438,10 @@ test test_hello ... FAILED
failures:
---- test_hello stdout ----
-[..]thread '[..]' panicked at 'assertion failed: false', \
- tests/footest.rs:1[..]
+[..]thread '[..]' panicked at [..]tests/footest.rs:1:[..]
",
)
+ .with_stdout_contains("[..]assertion failed[..]")
.with_stdout_contains(
"\
failures:
@@ -473,10 +474,10 @@ test test_hello ... FAILED
failures:
---- test_hello stdout ----
-[..]thread '[..]' panicked at 'assertion failed: false', \
- src/lib.rs:1[..]
+[..]thread '[..]' panicked at [..]src/lib.rs:1:[..]
",
)
+ .with_stdout_contains("[..]assertion failed[..]")
.with_stdout_contains(
"\
failures:
diff --git a/src/tools/cargo/triagebot.toml b/src/tools/cargo/triagebot.toml
index 00a98e008..6d07f438f 100644
--- a/src/tools/cargo/triagebot.toml
+++ b/src/tools/cargo/triagebot.toml
@@ -137,7 +137,7 @@ trigger_files = [
]
[autolabel."A-interacts-with-crates.io"]
-trigger_files = ["crates/crates-io/", "src/cargo/ops/registry.rs"]
+trigger_files = ["crates/crates-io/", "src/cargo/ops/registry/"]
[autolabel."A-layout"]
trigger_files = [
@@ -180,7 +180,7 @@ 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", "credential/"]
+trigger_files = ["src/cargo/util/auth/", "credential/"]
[autolabel."A-semver"]
trigger_files = [
@@ -266,10 +266,10 @@ trigger_files = ["src/bin/cargo/commands/install.rs", "src/cargo/ops/cargo_insta
trigger_files = ["src/bin/cargo/commands/locate_project.rs"]
[autolabel."Command-login"]
-trigger_files = ["src/bin/cargo/commands/login.rs"]
+trigger_files = ["src/bin/cargo/commands/login.rs", "src/cargo/ops/registry/login.rs"]
[autolabel."Command-logout"]
-trigger_files = ["src/bin/cargo/commands/logout.rs"]
+trigger_files = ["src/bin/cargo/commands/logout.rs", "src/cargo/ops/registry/logout.rs"]
[autolabel."Command-metadata"]
trigger_files = ["src/bin/cargo/commands/metadata.rs", "src/cargo/ops/cargo_output_metadata.rs"]
@@ -278,7 +278,7 @@ trigger_files = ["src/bin/cargo/commands/metadata.rs", "src/cargo/ops/cargo_outp
trigger_files = ["src/bin/cargo/commands/new.rs", "src/cargo/ops/cargo_new.rs"]
[autolabel."Command-owner"]
-trigger_files = ["src/bin/cargo/commands/owner.rs"]
+trigger_files = ["src/bin/cargo/commands/owner.rs", "src/cargo/ops/registry/owner.rs"]
[autolabel."Command-package"]
trigger_files = ["src/bin/cargo/commands/package.rs", "src/cargo/ops/cargo_package.rs"]
@@ -287,7 +287,7 @@ trigger_files = ["src/bin/cargo/commands/package.rs", "src/cargo/ops/cargo_packa
trigger_files = ["src/bin/cargo/commands/pkgid.rs", "src/cargo/ops/cargo_pkgid.rs"]
[autolabel."Command-publish"]
-trigger_files = ["src/bin/cargo/commands/publish.rs"]
+trigger_files = ["src/bin/cargo/commands/publish.rs", "src/cargo/ops/registry/publish.rs"]
[autolabel."Command-read-manifest"]
trigger_files = ["src/bin/cargo/commands/read_manifest.rs", "src/cargo/ops/cargo_read_manifest.rs"]
@@ -308,7 +308,7 @@ trigger_files = ["src/bin/cargo/commands/rustc.rs"]
trigger_files = ["src/bin/cargo/commands/rustdoc.rs"]
[autolabel."Command-search"]
-trigger_files = ["src/bin/cargo/commands/search.rs"]
+trigger_files = ["src/bin/cargo/commands/search.rs", "src/cargo/ops/registry/search.rs"]
[autolabel."Command-test"]
trigger_files = ["src/bin/cargo/commands/test.rs", "src/cargo/ops/cargo_test.rs"]
@@ -332,4 +332,4 @@ trigger_files = ["src/bin/cargo/commands/verify_project.rs"]
trigger_files = ["src/bin/cargo/commands/version.rs"]
[autolabel."Command-yank"]
-trigger_files = ["src/bin/cargo/commands/yank.rs"]
+trigger_files = ["src/bin/cargo/commands/yank.rs", "src/cargo/ops/registry/yank.rs"]